Skip to content

Instantly share code, notes, and snippets.

@besated
Last active November 19, 2024 03:15
Show Gist options
  • Save besated/55e6d443acaf026729a92ab567953c44 to your computer and use it in GitHub Desktop.
Save besated/55e6d443acaf026729a92ab567953c44 to your computer and use it in GitHub Desktop.
import secp256k1 from "secp256k1";
import { createPublicClient, createWalletClient, hexToNumber, http, numberToHex, parseSignature, toHex } from "viem";
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
import { seiTestnet } from "viem/chains";
import { ADDRESS_PRECOMPILE_ABI, ADDRESS_PRECOMPILE_ADDRESS } from '@sei-js/evm'
// replace pk
const PRIVATE_KEY = "";
const publicClient = createPublicClient({
chain: seiTestnet,
transport: http(),
});
const client = createWalletClient({
chain: seiTestnet,
transport: http(),
});
interface AssociateRequest {
r: string;
s: string;
v: string;
custom_message: string;
}
interface AssociateRequestSchema {
Method: 'sei_associate';
Parameters: [request: AssociateRequest];
ReturnType: null;
}
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Associate account using signed message
const associate = async () => {
const account = privateKeyToAccount(PRIVATE_KEY);
const newPk = generatePrivateKey();
const newAccount = privateKeyToAccount(newPk);
// Sign a message
const message = "associate"
const signature = await newAccount.signMessage({ message });
const parsedSignature = parseSignature(signature);
const messageLength = Buffer.from(message, 'utf8').length;
const signedMessage = `\x19Ethereum Signed Message:\n${messageLength}${message}`;
const response = await client.writeContract({
account,
address: ADDRESS_PRECOMPILE_ADDRESS,
abi: ADDRESS_PRECOMPILE_ABI,
functionName: "associate",
args: [numberToHex(Number(parsedSignature.v)-27), parsedSignature.r, parsedSignature.s, signedMessage],
gasPrice: BigInt(100_000_000_000), // 100 GWEI
});
console.log(response);
// Get evm address after association
await sleep(3000); // Sometimes it fails if you query it immeditely bc RPC nodes are behind
const evmAddress = await publicClient.readContract({
address: ADDRESS_PRECOMPILE_ADDRESS,
abi: ADDRESS_PRECOMPILE_ABI,
functionName: "getSeiAddr",
args: [newAccount.address],
});
console.log(evmAddress);
};
// Associate account using public key
const associateViaPubkey = async () => {
const account = privateKeyToAccount(PRIVATE_KEY);
const newPk = generatePrivateKey();
const newAccount = privateKeyToAccount(newPk);
// compress pubkey
const publicKeyBuffer = Buffer.from(newAccount.publicKey.slice(2), "hex");
const compressedPubKey = secp256k1.publicKeyConvert(publicKeyBuffer, true);
// console.log(newAccount.publicKey, toHex(compressedPublicKey));
const response = await client.writeContract({
account,
address: ADDRESS_PRECOMPILE_ADDRESS,
abi: ADDRESS_PRECOMPILE_ABI,
functionName: "associatePubKey",
args: [Buffer.from(compressedPubKey).toString("hex")],
gasPrice: BigInt(100_000_000_000), // 100 GWEI
});
console.log(response);
// Get evm address after association
await sleep(3000); // Sometimes it fails if you query it immeditely bc RPC nodes are behind
const evmAddress = await publicClient.readContract({
address: ADDRESS_PRECOMPILE_ADDRESS,
abi: ADDRESS_PRECOMPILE_ABI,
functionName: "getSeiAddr",
args: [newAccount.address],
});
console.log(evmAddress);
};
// Associate account using a signed message without gas (only allowed if the account already has funds)
const associateGasless = async (signature: `0x${string}`, message: string) => {
const parsedSignature = parseSignature(signature);
const messageLength = Buffer.from(message, 'utf8').length;
const messageToSign = `\x19Ethereum Signed Message:\n${messageLength}${message}`;
const request: AssociateRequest = {
r: parsedSignature.r,
s: parsedSignature.s,
v: numberToHex(Number(parsedSignature.v)-27),
custom_message: messageToSign
};
const response = await client.request<AssociateRequestSchema>({
method: 'sei_associate',
params: [request]
});
console.log(response);
}
const main = async () => {
associate();
// associateViaPubkey();
// associateGasless(signature, message);
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment