π Deploy a custom contracthttps://github.com/KintoXYZ/kinto-core/blob/main/script/actions/test.s.sol
This script:
Uses the KintoWallet to execute the count() operation through the Kinto AA EntryPoint
Step 1: Similarly to our previous script we initialize all contracts needed and check that AA abstraction is properly deployed.
Copy contract KintoDeployTestCounter is AASetup , KYCSignature , UserOp {
using ECDSAUpgradeable for bytes32 ;
using SignatureChecker for address ;
KintoID _kintoID;
EntryPoint _entryPoint;
KintoWalletFactory _walletFactory;
SponsorPaymaster _sponsorPaymaster;
IKintoWallet _newWallet;
function setUp () public {
uint256 deployerPrivateKey = vm. envUint ( 'TEST_PRIVATE_KEY' );
vm. startBroadcast (deployerPrivateKey);
(_kintoID , _entryPoint , _walletFactory , _sponsorPaymaster) = _checkAccountAbstraction ();
vm. stopBroadcast ();
}
Step 2: We use the KintoWalletFactory to check that the account already has a wallet and we retrieve it.
Copy function run () public {
uint256 deployerPrivateKey = vm. envUint ( 'TEST_PRIVATE_KEY' );
address deployerPublicKey = vm. rememberKey (vm. envUint ( "TEST_PRIVATE_KEY" ));
console. log ( 'All AA setup is correct' );
vm. startBroadcast (deployerPrivateKey);
uint salt = 0 ;
address newWallet = _walletFactory. getAddress (deployerPublicKey , deployerPublicKey , salt);
if ( ! isContract (newWallet)) {
console. log ( 'ERROR: Wallet not deployed for owner' , deployerPublicKey , 'at' , newWallet);
revert ();
}
_newWallet = IKintoWallet (newWallet);
Step 3: We check and retrieve the Counter if already deployed or use the KintoWalletFactory utility to deploy contracts (deployContract()).
Copy // Counter contract
address computed = _walletFactory. getContractAddress (
bytes32 ( 0 ) , keccak256 (abi. encodePacked (type(Counter).creationCode)));
if ( ! isContract (computed)) {
address created = _walletFactory. deployContract ( 0 ,
abi. encodePacked (type(Counter).creationCode) , bytes32 ( 0 ));
console. log ( 'Deployed Counter contract at' , created);
} else {
console. log ( 'Counter already deployed at' , computed);
}
Counter counter = Counter (computed);
Step 4: We check the balance of our Counter contract in the SponsorPaymaster (with balances(address)) and then we addDepositFor{value}(counterAddress).
Copy
console. log ( 'Before UserOp. Counter:' , counter. count ());
// We add the deposit to the counter contract in the paymaster
if (_sponsorPaymaster. balances (computed) <= 1e14 ) {
_sponsorPaymaster.addDepositFor{value : 5e16 }(computed);
console. log ( 'Adding paymaster balance to counter' , computed);
} else {
console. log ( 'Counter already has balance to pay for tx' , computed);
}
Step 5: Before calling the method. You will also need to give permission to the wallet to interact with that contract.
Copy address [] memory apps = new address []( 1 );
apps[ 0 ] = < CONTRACT_ ADDRESS > ;
bool [] memory flags = new bool []( 1 );
flags[ 0 ] = true ;
_handleOps(abi.encodeWithSelector(IKintoWallet.whitelistApp.selector, apps, flags), _wallet, _wallet, _signerPk);// Some code
Step 6: In AA, all operations need to be pack in a UserOperation, we can do this thanks to the KintoWallet .
Copy // Let's send a transaction to the counter contract through our wallet
uint startingNonce = _newWallet. getNonce ();
uint256 [] memory privateKeys = new uint256 []( 1 );
privateKeys[ 0 ] = deployerPrivateKey;
UserOperation memory userOp = this . createUserOperationWithPaymasterCustomGas (
block.chainid ,
address (_newWallet) ,
startingNonce ,
privateKeys ,
address (counter) ,
0 ,
abi. encodeWithSignature ( 'increment()' ) ,
address (_sponsorPaymaster) ,
[ uint256 ( 5000000 ) , 3 , 3 ]
);
UserOperation[] memory userOps = new UserOperation[]( 1 );
userOps[ 0 ] = userOp;
Step 6: Execute the transaction via the entry point .
Copy _entryPoint. handleOps (userOps , payable (deployerPublicKey));
console. log ( 'After UserOp. Counter:' , counter. count ());
vm. stopBroadcast ();
}
}