Skip to content

Instantly share code, notes, and snippets.

@byeongsu-hong
Created March 8, 2024 13:26
Show Gist options
  • Save byeongsu-hong/566c26e5750f34afbb240f4a17f09b47 to your computer and use it in GitHub Desktop.
Save byeongsu-hong/566c26e5750f34afbb240f4a17f09b47 to your computer and use it in GitHub Desktop.
KAS Escape
import {
Address,
Hex,
LocalAccount,
Signature,
createWalletClient,
http,
keccak256,
parseEther,
recoverAddress,
recoverPublicKey,
serializeTransaction,
} from 'viem';
import { mainnet } from 'viem/chains';
const krn = process.env.KRN;
const username = process.env.USERNAME;
const password = process.env.PASSWORD;
if (!krn || !username || !password)
throw new Error('KRN, USERNAME, PASSWORD are required');
async function requestSign(
{
krn,
username,
password,
}: { krn: string; username: string; password: string },
chainId: number,
hash: Hex,
): Promise<{ signature: Signature; address: Address; publicKey: Hex }> {
const resp = await fetch(
`https://wallet-api.klaytnapi.com/v2/key/${krn}/sign`,
{
method: 'POST',
headers: {
Authorization:
'Basic ' + Buffer.from(username + ':' + password).toString('base64'),
'Content-Type': 'application/json',
'x-chain-id': `${chainId}`,
},
body: JSON.stringify({ data: hash }),
},
);
const respBody: {
signature: {
R: Hex;
S: Hex;
V: Hex;
};
signedData: Hex;
} = await resp.json();
const address = await recoverAddress({
hash,
signature: respBody.signedData,
});
const publicKey = await recoverPublicKey({
hash,
signature: respBody.signedData,
});
return {
signature: {
v: BigInt(respBody.signature.V),
r: respBody.signature.R,
s: respBody.signature.S,
},
address,
publicKey,
};
}
async function createKASWallet(credential: {
krn: string;
username: string;
password: string;
}): Promise<LocalAccount<'wallet'>> {
const { address, publicKey } = await requestSign(
credential,
1,
keccak256('0xdeadbeef'),
);
return {
address,
publicKey,
source: 'wallet',
type: 'local',
async signMessage() {
throw new Error('not implemented');
},
async signTypedData() {
throw new Error('not implemented');
},
async signTransaction(transaction, args) {
const serializer = args?.serializer || serializeTransaction;
const hash = keccak256(serializer(transaction));
if (!transaction.chainId) throw new Error('chainId is required');
const { signature } = await requestSign(
credential,
transaction.chainId,
hash,
);
return serializer(transaction, signature);
},
};
}
async function main() {
const client = createWalletClient({
chain: mainnet,
transport: http(),
account: await createKASWallet({
krn: krn!,
username: username!,
password: password!,
}),
});
const resp = await client.sendTransaction({
to: client.account.address,
value: parseEther('1'),
});
console.log(resp);
}
main().catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment