Created
June 24, 2025 18:38
-
-
Save NetanelBasal/b200dd655f78b119ea9623cf1bc95780 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
createWalletClient, | |
encodeFunctionData, | |
http, | |
parseEther, | |
Hex, | |
createPublicClient, | |
encodePacked, | |
keccak256, | |
parseAbi, | |
} from "viem"; | |
import { keys } from "./keys/keys.js"; | |
import { sepolia } from "viem/chains"; | |
import { privateKeyToAccount, sign } from "viem/accounts"; | |
const netanel = privateKeyToAccount(keys.netanel.privateKey); | |
const tal = privateKeyToAccount(keys.tal.privateKey); | |
const contractAddress: Hex = "0x033eA0ff6b6C63032F95cA1796791D2FFAD9677B"; | |
const batchCallAndSponsor: Hex = "0xBDBA7F921f8C8AFF014749Fc17324e832291bfB0"; | |
const netanelWalletClient = createWalletClient({ | |
account: netanel, | |
chain: sepolia, | |
transport: http(), | |
}); | |
const talWalletClient = createWalletClient({ | |
account: tal, | |
chain: sepolia, | |
transport: http(), | |
}); | |
const readClient = createPublicClient({ | |
chain: sepolia, | |
transport: http(), | |
}); | |
const abi = parseAbi(["function ping() returns (address caller)"]); | |
const batchAbi = parseAbi([ | |
"function execute((address to,uint256 value,bytes data)[] calls,bytes signature) payable", | |
"function execute((address to,uint256 value,bytes data)[] calls) payable", | |
"function nonce() view returns (uint256)", | |
]); | |
function toEthSignedMessageHash(messageHash: Hex): Hex { | |
return keccak256( | |
encodePacked( | |
["string", "bytes32"], | |
["\x19Ethereum Signed Message:\n32", messageHash] | |
) | |
); | |
} | |
export async function netanelPaysFlow() { | |
const batchCalls = [ | |
{ | |
to: contractAddress, | |
value: 0n, | |
data: encodeFunctionData({ abi, functionName: "ping" }), | |
}, | |
{ | |
to: "0x8C02B437016118aA9bca0EEE178Dc3eB7E175E87", | |
value: parseEther("0.01"), | |
data: "0x", | |
}, | |
] as const; | |
const data = encodeFunctionData({ | |
abi: batchAbi, | |
functionName: "execute", | |
args: [batchCalls], | |
}); | |
const authorization = await netanelWalletClient.signAuthorization({ | |
executor: "self", | |
contractAddress: batchCallAndSponsor, | |
}); | |
const txHash = await netanelWalletClient.sendTransaction({ | |
to: netanel.address, | |
data, | |
authorizationList: [authorization], | |
}); | |
console.log( | |
"✅ Netanel paid & sent tx:", | |
`https://eth-sepolia.blockscout.com/tx/${txHash}` | |
); | |
} | |
// ─── Flow 2: Tal Pays (Delegated Execution) ────────────────────────────── | |
export async function talPaysFlow() { | |
const batchCalls = [ | |
{ | |
to: contractAddress, | |
value: 0n, | |
data: encodeFunctionData({ abi, functionName: "ping" }), | |
}, | |
{ | |
to: "0x8C02B437016118aA9bca0EEE178Dc3eB7E175E87", | |
value: parseEther("0.01"), | |
data: "0x", | |
} as const, | |
]; | |
const encodedCall = encodePacked( | |
["address", "uint256", "bytes", "address", "uint256", "bytes"], | |
[ | |
batchCalls[0].to, | |
batchCalls[0].value, | |
batchCalls[0].data, | |
batchCalls[1].to, | |
batchCalls[1].value, | |
batchCalls[1].data, | |
] | |
); | |
const nonce = await readClient.readContract({ | |
address: netanel.address, | |
abi: batchAbi, | |
functionName: "nonce", | |
}); | |
const digest = keccak256( | |
encodePacked(["uint256", "bytes"], [BigInt(nonce), encodedCall]) | |
); | |
const signature = await sign({ | |
hash: toEthSignedMessageHash(digest), | |
privateKey: keys.netanel.privateKey, | |
to: "hex", | |
}); | |
const data = encodeFunctionData({ | |
abi: batchAbi, | |
functionName: "execute", | |
args: [batchCalls, signature], | |
}); | |
const txHash = await talWalletClient.sendTransaction({ | |
to: netanel.address, | |
data, | |
}); | |
console.log( | |
"✅ Tal paid gas & sent tx for Netanel:", | |
`https://eth-sepolia.blockscout.com/tx/${txHash}` | |
); | |
} | |
async function main() { | |
// await netanelPaysFlow(); | |
// await talPaysFlow(); | |
} | |
main().catch(console.error); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment