A secure cross chain smart wallet.
View Demo
·
Screenshots
DPI (yes it's inspired from UPI) stands for decentralized payment interface, it is a non-custodial payment interface for on chain payments.Users are provided with a single DPI ID which hold their assets and it the same for all the EVM based chains(ain't that cool 🤯).Powered by Connext to enable cross chain bridging DPI offers quick and resilient mode of transfers both on the host chain and for payments across chains.Payments are gasless which are verified and submitted through smart wallets. DPI operates on three layers :
-
Smart wallet contract deployer : Smart wallets are deployed via a factory contract which ensures and predetermines the address of the smart wallet contract the user can deploy.
-
Smart wallet contract : Smart wallets contain exec() function which is provided with data in the form of user operations which are executed in a single transaction. ECDSASmartWallet is responsible for verifying signature for the data received from the user.The injected provider configured to any chain can be used to sign transactions for any other chain.
-
DPI UX: This layer generates data for user operations ,displays data or context , gets them signed by the user and bundles them into a single call.
Polygon - best Defi project(s) , best UX Deployed Contract links : Polygon : https://mumbai.polygonscan.com/address/0x0bfe22aACCeEDE01FAa0d24651431Fc2f8cc4437
- The signature verification in smart wallet is efficient and secure.It is verified via the following checks and calculations :
address signer = domainSeperator(_sigChainID).toTypedDataHash(
keccak256(
abi.encode(_TYPEHASH,
hash(_userOps),
nonce(),
block.chainid,
_sigChainID)
)
).recover(_sig);
require(state().owner == signer, "ECDSAWallet: failed to verify signature");
- Where type hash is given by :
bytes32 private constant _TYPEHASH =
keccak256("ECDSAExec(UserOp[] userOps,uint256 nonce,uint256 chainID,uint256 sigChainID)UserOp(address to,uint256 amount,bytes data)");
- Hash function is responsible for generating a aggregated hash via
function hash(UserOp[] memory _userOps) internal pure returns (bytes32) {
bytes32[] memory opHashes = new bytes32[](_userOps.length);
for (uint i = 0; i < _userOps.length; i++) {
opHashes[i] = keccak256(abi.encode(UserOp_TYPE_HASH, _userOps[i].to, _userOps[i].amount, keccak256(_userOps[i].data)));
}
return keccak256(abi.encodePacked(opHashes));
}
- Where UserOp_TYPE_HASH is given by :
bytes32 private constant UserOp_TYPE_HASH =
keccak256("UserOp(address to,uint256 amount,bytes data)");
- The smart wallet contract address is generated via the following :
return address(uint160(uint(keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
keccak256(abi.encode(callID, _nonce)),
keccak256(abi.encodePacked(
type(ERC1967Proxy).creationCode,
abi.encode(_impl, _call)
)))))));
- This ensure that the user receives the generated address as their smart wallet address no matter when the deploy their contract.
- Funds can be transferred to address before a contract exists at the address and the funds will be available to the user when the contract is deployed.
The contract implementations can be found in /backend/contracts (https://github.com/r4reetik/dpi/tree/main/backend/contracts)
The data display to the user for signing is formatted in the form of :
const domain = {
name: "ECDSAWallet",
version: "0.0.1",
chainId: chainID,
verifyingContract: smartWalletAddress,
};
const types = {
UserOp: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
{ name: "data", type: "bytes" },
],
ECDSAExec: [
{ name: "userOps", type: "UserOp[]" },
{ name: "nonce", type: "uint256" },
{ name: "chainID", type: "uint256" },
{ name: "sigChainID", type: "uint256" },
],
};
const value = {
userOps: userOps,
nonce: nonce,
chainID: chainID,
sigChainID: signatureChainID,
};
For both app and backend environment :
- yarn
DPI UX is implemented as a web app which can be used to send and receive payments across chains.As a payments interface it is non-custodial and the user is in full control of their assets.Transfers are the key feature of the app and it is powered by Connext to enable cross chain transfers.Push protocol is used to enable reliable transaction notification.Contracts are deployed on every EVM based chains and the user can deploy smart wallets on any of the supported chains. The user can :
- Create a smart wallet at deterministic address.
- Fund the smart wallet with any supported token.
- Send and receive payments across chains via ENS or public addresses.
- Use QR code to send and receive payments.
- Designed and implemented smart wallet and factory contracts
- Added ECDSA verification for smart wallet
- Designed and implemented DPI UX
- Adder support for ERC20 tokens transfer and cross chain transfers
- Added support for qr scanning
Features proposed for future :
- Add support for generating populated data for all kinds of transactions on UI
- Add EDDSA signature verification in smart wallets
- Add compatibility support for EIP4337
This repo is a part of the project DPI (Decentralized Payment Interface) which is a part of the hackathon hosted by ETHIndia and Devfolio.