Skip to content

Commit

Permalink
chore: refactoring and demo scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
idea404 committed Nov 12, 2023
1 parent 27d64b6 commit c3c0141
Show file tree
Hide file tree
Showing 11 changed files with 260 additions and 217 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

bytes4 constant EIP1271_SUCCESS_RETURN_VALUE = 0x1626ba7e;

contract SharedAccountWithRestrictions is IAccount, IERC1271, IERC721Receiver {
contract SharedRestrictedAccount is IAccount, IERC1271, IERC721Receiver {
using TransactionHelper for Transaction;

address private admin;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.17;
import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol";
import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol";

contract SharedAccountWithRestrictionsFactory {
contract SharedRestrictedAccountFactory {
bytes32 public aaBytecodeHash;

constructor(bytes32 _aaBytecodeHash) {
Expand Down
36 changes: 36 additions & 0 deletions demo/shared-restricted-fund.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// This script will:
// 1. Send ETH to the shared restricted account

import { ethers } from "ethers";
import { Provider, Wallet } from "zksync-web3";
import { getDeployedContractDetailsFromVars, config } from "../deploy/utils";

const NETWORK = "zkSyncLocalnet";
const RPC_URL = config.L2RpcUrl;
const PRIVATE_KEY = config.firstWalletPrivateKey;

async function main() {
const provider = new Provider(RPC_URL);
const mainWallet = new Wallet(PRIVATE_KEY, provider);

// Load the contract address from vars.json
const accountAddress = getDeployedContractDetailsFromVars(NETWORK, "SharedRestrictedAccount").address;
// send 100 ETH to the paAddress
const balance = await provider.getBalance(accountAddress);
const tx = await mainWallet.sendTransaction({
to: accountAddress,
value: ethers.utils.parseEther("100"),
});
await tx.wait();
const newBalance = await provider.getBalance(accountAddress);
console.log(`Sent 100 ETH to Pension Account at: ${accountAddress}`);
console.log(`Balance before: ${ethers.utils.formatEther(balance)} ETH`);
console.log(`Balance after: ${ethers.utils.formatEther(newBalance)} ETH`);
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
16 changes: 0 additions & 16 deletions deploy/deploy-shared-account-with-restrictions.ts

This file was deleted.

34 changes: 34 additions & 0 deletions deploy/deploy-shared-restricted.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Wallet, Provider, utils } from "zksync-web3";
import { HardhatRuntimeEnvironment, HttpNetworkConfig } from "hardhat/types";
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
import { config, saveContractToVars } from "../deploy/utils";
import { ethers } from "ethers";

const KEY = config.firstWalletPrivateKey;

export default async function (hre: HardhatRuntimeEnvironment) {
const provider = new Provider({ url: (hre.network.config as HttpNetworkConfig).url });
const wallet = new Wallet(KEY).connect(provider);
const deployer = new Deployer(hre, wallet);
const accountFactoryArtifact = await deployer.loadArtifact("SharedRestrictedAccountFactory");
const accountArtifact = await deployer.loadArtifact("SharedRestrictedAccount");

// Deploy the factory
const bytecodeHash = utils.hashBytecode(accountArtifact.bytecode);
const factory = await deployer.deploy(accountFactoryArtifact, [bytecodeHash], undefined, [accountArtifact.bytecode]);
console.log(`SharedRestrictedAccountFactory address: ${factory.address}`);
saveContractToVars(hre.network.name, "SharedRestrictedAccountFactory", factory.address);

// Deploy the account
const salt = ethers.constants.HashZero;

// deploy account owned by owner1 & owner2
const tx = await factory.deployAccount(salt, wallet.address);
await tx.wait();

// Getting the address of the deployed contract account
const abiCoder = new ethers.utils.AbiCoder();
let accountAddress = utils.create2Address(factory.address, await factory.aaBytecodeHash(), salt, abiCoder.encode(["address"], [wallet.address]));
console.log(`SharedRestrictedAccount address: ${accountAddress}`);
saveContractToVars(hre.network.name, "SharedRestrictedAccount", accountAddress);
}
12 changes: 10 additions & 2 deletions deploy/vars.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@
"deployed": [
{
"name": "PensionAccountFactory",
"address": "0x111C3E89Ce80e62EE88318C2804920D4c96f92bb"
"address": "0x094499Df5ee555fFc33aF07862e43c90E6FEe501"
},
{
"name": "PensionAccount",
"address": "0x58d487F21a6baCDAC552dfce6EE09365bD52dbE1"
"address": "0xafA540E68a4e544d604277311190a0AC2CA6B8E6"
},
{
"name": "SharedRestrictedAccountFactory",
"address": "0xb76eD02Dea1ba444609602BE5D587c4bFfd67153"
},
{
"name": "SharedRestrictedAccount",
"address": "0x542baA36793feE02404c081B26284120af899428"
}
]
}
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
"license": "MIT",
"scripts": {
"test": "hardhat test --network hardhat",
"deploy:shared-account-with-restrictions": "hardhat deploy-zksync --script deploy-shared-account-with-restrictions.ts --network zkSyncLocalnet",
"deploy:shared-restricted": "hardhat deploy-zksync --script deploy-shared-restricted.ts --network zkSyncLocalnet",
"deploy:aafactory": "hardhat deploy-zksync --script deploy-aafactory.ts --network zkSyncLocalnet",
"deploy:multisig": "hardhat deploy-zksync --script deploy-multisig.ts --network zkSyncLocalnet",
"deploy:pafactory": "hardhat deploy-zksync --script deploy-pafactory.ts --network zkSyncLocalnet",
"deploy:pension": "hardhat deploy-zksync --script deploy-pension.ts --network zkSyncLocalnet",
"demo:pension-setup": "yarn deploy:pafactory && yarn deploy:pension && yarn demo:pension-fund",
"demo:pension-fund": "ts-node demo/pension-fund-eth.ts",
"demo:pension-withdraw": "ts-node demo/pension-send-eth.ts",
"demo:shared-restricted-setup": "yarn deploy:shared-restricted && yarn demo:shared-restricted-fund",
"demo:shared-restricted-fund": "ts-node demo/shared-restricted-fund.ts",
"demo:fast-forward": "ts-node demo/fast-forward.ts"
},
"devDependencies": {
Expand Down
149 changes: 146 additions & 3 deletions test/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ import { expect } from "chai";
import * as hre from "hardhat";
import { ethers } from "ethers";
import * as zks from "zksync-web3";
import { deployFactory, deployMultisig, fundAccount, MultiSigWallet, deployPension, PensionWallet, advanceBlocks } from "./utils";
import { deployFactory, deployMultisig, fundAccount, MultiSigWallet, deployPension, SingleSignerAAWallet, advanceBlocks, deploySharedRestricted, deployContract } from "./utils";

const config = {
firstWalletPrivateKey: "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110",
firstWalletAddress: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049",
secondWalletPrivateKey: "0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3",
secondWalletAddress: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618",
thirdWalletPrivateKey: "0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e",
thirdWalletAddress: "0x0D43eB5B8a47bA8900d84AA36656c92024e9772e",
};

describe("Account Abstraction Tests", function () {
Expand Down Expand Up @@ -145,7 +149,7 @@ describe("Account Abstraction Tests", function () {
});

it("Should not be able to withdraw before the lockup period", async function () {
const pensionWallet = new PensionWallet(
const pensionWallet = new SingleSignerAAWallet(
pensionAccountContract.address,
ownerWallet.privateKey,
provider
Expand Down Expand Up @@ -173,7 +177,7 @@ describe("Account Abstraction Tests", function () {
// Advance the blockchain by 10 blocks
await advanceBlocks(10);

const pensionWallet = new PensionWallet(
const pensionWallet = new SingleSignerAAWallet(
pensionAccountContract.address,
ownerWallet.privateKey,
provider
Expand All @@ -196,4 +200,143 @@ describe("Account Abstraction Tests", function () {
});
});
});

describe("Shared Restricted Account Abstraction Tests", function () {
const accountContractName = "SharedRestrictedAccount";
const factoryContractName = "SharedRestrictedAccountFactory";
let factoryContract: ethers.Contract;
describe("Shared Restricted Account Factory", function () {
before(async function () {
factoryContract = await deployFactory(firstRichWallet, accountContractName, factoryContractName);
});

it("Should have a tx hash that starts from 0x", async function () {
result = factoryContract.deployTransaction.hash;
expect(result).to.contains("0x");
});
});

describe("Shared Restricted Account", function () {
const firstOwnerWallet = new zks.Wallet(config.secondWalletPrivateKey, provider);
const secondOwnerWallet = new zks.Wallet(config.thirdWalletPrivateKey, provider);
let sharedRestrictedAccountContract: ethers.Contract;
let testContract1: ethers.Contract;
let testContract2: ethers.Contract;
let testContract3: ethers.Contract;
before(async function () {
sharedRestrictedAccountContract = await deploySharedRestricted(firstRichWallet, factoryContract.address, firstRichWallet);
await fundAccount(firstRichWallet, sharedRestrictedAccountContract.address);
testContract1 = await deployContract(firstRichWallet, "TestContract");
testContract2 = await deployContract(firstRichWallet, "TestContract");
testContract3 = await deployContract(firstRichWallet, "TestContract");
});

it("Should have a tx hash that starts from 0x", async function () {
result = factoryContract.deployTransaction.hash;
expect(result).to.contains("0x");
});

it("Should have to owners initially", async function () {
const owners = await sharedRestrictedAccountContract.getOwners();
expect(owners.length).to.equal(0);
});

it("Should be able to add owners", async function () {
const tx = await sharedRestrictedAccountContract.addOwner(firstOwnerWallet.address);
await tx.wait();
const owners = await sharedRestrictedAccountContract.getOwners();
expect(owners.length).to.equal(1);
expect(owners[0]).to.equal(firstOwnerWallet.address);
const tx2 = await sharedRestrictedAccountContract.addOwner(secondOwnerWallet.address);
await tx2.wait();
const owners2 = await sharedRestrictedAccountContract.getOwners();
expect(owners2.length).to.equal(2);
expect(owners2[0]).to.equal(firstOwnerWallet.address);
expect(owners2[1]).to.equal(secondOwnerWallet.address);
});

it("Should have no allowed call addresses initially", async function () {
const allowedCallAddresses = await sharedRestrictedAccountContract.getAllowedCallAddresses();
expect(allowedCallAddresses.length).to.equal(0);
});

it("Should be able to add allowed call addresses", async function () {
const tx = await sharedRestrictedAccountContract.addAllowedCallAddress(testContract1.address, [
testContract1.interface.getSighash('testFunction1')
]);
await tx.wait();
const allowedCallAddresses = await sharedRestrictedAccountContract.getAllowedCallAddresses();
expect(allowedCallAddresses.length).to.equal(1);
expect(allowedCallAddresses[0]).to.equal(testContract1.address);
const tx2 = await sharedRestrictedAccountContract.addAllowedCallAddress(testContract2.address, [
testContract2.interface.getSighash('testFunction2')
]);
await tx2.wait();
const allowedCallAddresses2 = await sharedRestrictedAccountContract.getAllowedCallAddresses();
expect(allowedCallAddresses2.length).to.equal(2);
expect(allowedCallAddresses2[0]).to.equal(testContract1.address);
expect(allowedCallAddresses2[1]).to.equal(testContract2.address);
});

it("Should not be able to use account with some random wallet", async function () {
const randomWallet = zks.Wallet.createRandom();
const accountWallet = new SingleSignerAAWallet(
sharedRestrictedAccountContract.address,
randomWallet.privateKey,
provider
);
try {
accountWallet.transfer({
to: firstRichWallet.address,
amount: ethers.utils.parseUnits("1", 18),
overrides: { type: 113 },
});
} catch (e) {
expect(e.message).to.contains("execution reverted: Account validation error");
}
});

it("Should be able to use account with owner wallet and allowed contract method", async function () {
const accountWallet = new SingleSignerAAWallet(
sharedRestrictedAccountContract.address,
firstOwnerWallet.privateKey,
provider
);
const testContract1accountWallet = testContract1.connect(accountWallet);
const result = await testContract1accountWallet.testFunction1(firstOwnerWallet.address);
expect(result).to.equal(firstOwnerWallet.address);
const testContract2accountWallet = testContract2.connect(accountWallet);
const result2 = await testContract2accountWallet.testFunction2();
expect(result2).to.equal(true);
});

it("Should not be able to use account with owner wallet and not allowed call address", async function () {
const accountWallet = new SingleSignerAAWallet(
sharedRestrictedAccountContract.address,
firstOwnerWallet.privateKey,
provider
);
const testContract3accountWallet = testContract3.connect(accountWallet);
try {
testContract3accountWallet.testFunction1(firstOwnerWallet.address);
} catch (e) {
expect(e.message).to.contains("execution reverted: Account validation error");
}
});

it("Should not be able to use account with owner wallet and allowed call address but not allowed method", async function () {
const accountWallet = new SingleSignerAAWallet(
sharedRestrictedAccountContract.address,
firstOwnerWallet.privateKey,
provider
);
const testContract1accountWallet = testContract1.connect(accountWallet);
try {
testContract1accountWallet.testFunction3();
} catch (e) {
expect(e.message).to.contains("execution reverted: Account validation error");
}
});
});
});
});
Loading

0 comments on commit c3c0141

Please sign in to comment.