Skip to content

Commit 82709c7

Browse files
authored
Merge pull request #2524 from AmbireTech/feature/safe-sponsorship
Feature/safe sponsorship
2 parents 7d3e4d2 + e002b4e commit 82709c7

22 files changed

Lines changed: 1788 additions & 249 deletions

File tree

contracts/compiled/SafeNoSignatureValidation.json

Lines changed: 1003 additions & 0 deletions
Large diffs are not rendered by default.

hardhat.config.ts

Lines changed: 90 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ import { HardhatUserConfig } from 'hardhat/config'
77

88
require('dotenv').config()
99

10+
const accounts = process.env.PRIVATE_KEY
11+
? [
12+
process.env.PRIVATE_KEY,
13+
...(process.env.PAYMASTER_PRIVATE_KEY ? [process.env.PAYMASTER_PRIVATE_KEY] : [])
14+
]
15+
: undefined
16+
1017
const config: HardhatUserConfig = {
1118
solidity: {
1219
version: '0.8.19',
@@ -32,79 +39,119 @@ const config: HardhatUserConfig = {
3239
networks: {
3340
base: {
3441
url: 'https://mainnet.base.org',
35-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
42+
accounts
3643
},
3744
monad: {
3845
url: 'https://rpc.monad.xyz',
39-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
46+
accounts
47+
},
48+
polygon: {
49+
url: 'https://invictus.ambire.com/polygon',
50+
accounts
51+
},
52+
mantle: {
53+
url: 'https://invictus.ambire.com/mantle',
54+
accounts
55+
},
56+
plasma: {
57+
url: 'https://rpc.plasma.to',
58+
accounts
59+
},
60+
avalanche: {
61+
url: 'https://invictus.ambire.com/avalanche',
62+
accounts
63+
},
64+
ink: {
65+
url: 'https://invictus.ambire.com/ink',
66+
accounts
67+
},
68+
hype: {
69+
url: 'https://invictus.ambire.com/hyperevm',
70+
accounts
4071
},
4172
baseSepolia: {
4273
url: 'https://sepolia.base.org',
43-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
74+
accounts
4475
},
4576
opSepolia: {
4677
url: 'https://sepolia.optimism.io',
47-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
78+
accounts
4879
},
4980
sepolia: {
5081
url: 'https://invictus.ambire.com/sepolia',
51-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
82+
accounts
5283
},
5384
arbSepolia: {
5485
url: 'https://sepolia-rollup.arbitrum.io/rpc',
55-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
86+
accounts
5687
},
5788
optimism: {
5889
url: 'https://invictus.ambire.com/optimism',
59-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
90+
accounts
6091
},
6192
odyssey: {
6293
url: 'https://odyssey.ithaca.xyz',
63-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
94+
accounts
6495
},
6596
ethereum: {
6697
url: 'https://invictus.ambire.com/ethereum',
67-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
98+
accounts
6899
},
69100
linea: {
70101
url: 'https://linea-rpc.publicnode.com',
71-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
102+
accounts
72103
},
73104
binance: {
74105
url: 'https://invictus.ambire.com/binance-smart-chain',
75-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
106+
accounts
76107
},
77108
gnosis: {
78109
url: 'https://rpc.gnosischain.com',
79-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
110+
accounts
80111
},
81112
unichain: {
82113
url: 'https://unichain-rpc.publicnode.com',
83-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
114+
accounts
84115
},
85116
berachain: {
86117
url: 'https://rpc.berachain-apis.com',
87-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
118+
accounts
88119
},
89120
arbitrum: {
90121
url: 'https://invictus.ambire.com/arbitrum',
91-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
122+
accounts
92123
},
93124
berachainBepolia: {
94125
url: 'https://bepolia.rpc.berachain.com',
95-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
126+
accounts
96127
},
97128
katana: {
98129
url: 'https://rpc.katana.network',
99-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
130+
accounts
100131
},
101132
world: {
102133
url: 'https://invictus.ambire.com/world',
103-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
134+
accounts
104135
},
105136
celo: {
106137
url: 'https://forno.celo.org',
107-
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : undefined
138+
accounts
139+
},
140+
robinhood: {
141+
url: 'https://rpc.mainnet.chain.robinhood.com',
142+
accounts
143+
},
144+
megaeth: {
145+
url: 'https://mainnet.megaeth.com/rpc',
146+
accounts
147+
},
148+
scroll: {
149+
url: 'https://invictus.ambire.com/scroll',
150+
accounts
151+
},
152+
kaia: {
153+
url: 'https://public-en.node.kaia.io',
154+
accounts
108155
}
109156
},
110157
etherscan: {
@@ -270,6 +317,30 @@ const config: HardhatUserConfig = {
270317
browserURL: 'https://monadvision.com'
271318
}
272319
},
320+
{
321+
network: 'polygon',
322+
chainId: 137,
323+
urls: {
324+
apiURL: 'https://api.polygonscan.com/api',
325+
browserURL: 'https://api.polygonscan.com'
326+
}
327+
},
328+
{
329+
network: 'mantle',
330+
chainId: 5000,
331+
urls: {
332+
apiURL: 'https://api.mantlescan.xyz/api',
333+
browserURL: 'https://api.mantlescan.xyz'
334+
}
335+
},
336+
{
337+
network: 'plasma',
338+
chainId: 9745,
339+
urls: {
340+
apiURL: 'https://api.plasmascan.to/api',
341+
browserURL: 'https://plasmascan.to'
342+
}
343+
},
273344
{
274345
network: 'world',
275346
chainId: 480,

scripts/deploySafeSenderAccount.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
require('dotenv').config()
2+
3+
const { ethers, network } = require('hardhat')
4+
const { Interface, keccak256, AbiCoder } = require('ethers')
5+
const AmbireFactory = require('../contracts/compiled/AmbireFactory.json')
6+
const { AMBIRE_ACCOUNT_FACTORY, AMBIRE_PAYMASTER_SIGNER } = require('@/consts/deploy')
7+
const { getSmartAccount } = require('@/libs/account/account')
8+
const { callToTuple } = require('@/libs/accountOp/accountOp')
9+
const { getActivatorCall } = require('@/libs/userOperation/userOperation')
10+
11+
function wrapTypedData(chainId, verifyingAddr, executeHash) {
12+
const domain = {
13+
name: 'Ambire',
14+
version: '1',
15+
chainId: chainId.toString(),
16+
verifyingContract: verifyingAddr,
17+
salt: ethers.toBeHex(0, 32)
18+
}
19+
const types = {
20+
AmbireOperation: [
21+
{ name: 'account', type: 'address' },
22+
{ name: 'hash', type: 'bytes32' }
23+
]
24+
}
25+
const value = {
26+
account: verifyingAddr,
27+
hash: executeHash
28+
}
29+
30+
return {
31+
domain,
32+
types,
33+
value
34+
}
35+
}
36+
37+
async function main() {
38+
const [deployer, paymasterSigner] = await ethers.getSigners()
39+
40+
const ambireFactory = new Interface(AmbireFactory.abi)
41+
const account = await getSmartAccount(
42+
[
43+
{
44+
addr: AMBIRE_PAYMASTER_SIGNER,
45+
hash: '0x0000000000000000000000000000000000000000000000000000000000000002' // full perm
46+
}
47+
],
48+
[]
49+
)
50+
const providerNetwork = await ethers.provider.getNetwork()
51+
const network = await ethers.provider.getNetwork()
52+
const chainId = network.chainId
53+
const abiCoder = new AbiCoder()
54+
const entryPointAuthTxns = [callToTuple(getActivatorCall(account.addr))]
55+
const executeHash = keccak256(
56+
abiCoder.encode(
57+
['address', 'uint', 'uint', 'tuple(address, uint, bytes)[]'],
58+
[account.addr, chainId, 0n, entryPointAuthTxns]
59+
)
60+
)
61+
const typedData = wrapTypedData(chainId, account.addr, executeHash)
62+
const s = await paymasterSigner.signTypedData(typedData.domain, typedData.types, typedData.value)
63+
const signature = `${s}01`
64+
65+
const tx = {
66+
to: AMBIRE_ACCOUNT_FACTORY,
67+
value: 0n,
68+
data: ambireFactory.encodeFunctionData('deployAndExecute', [
69+
account.creation.bytecode,
70+
account.creation.salt,
71+
entryPointAuthTxns,
72+
signature
73+
]),
74+
gasLimit: 2000000n
75+
}
76+
77+
// Send the transaction
78+
const txResponse = await deployer.sendTransaction(tx)
79+
80+
// Wait for the transaction to be mined
81+
const txReceipt = await txResponse.wait()
82+
83+
console.log('Transaction sent!')
84+
console.log(txReceipt)
85+
}
86+
87+
main().catch((error) => {
88+
console.error(error)
89+
process.exit(1)
90+
})

src/consts/deploy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ export const EIP_7702_AMBIRE_ACCOUNT = '0x5A7FC11397E9a8AD41BF10bf13F22B0a63f96f
1919
export const EIP_7702_METAMASK = '0x63c0c19a282a1B52b07dD5a65b58948A07DAE32B'
2020
export const EIP_7702_GRID_PLUS = '0x8D6220c9961E8DD1844108C854F514E120226E20'
2121
export const EIP_7702_KATANA = '0x8226995E02C70293595E0634C5F89547EDb08126'
22+
export const SAFE_SENDER = '0x3979FF5F4DF3128dd05b3d74CF9b7F462e0d9BF1'

0 commit comments

Comments
 (0)