Created
March 8, 2024 13:26
-
-
Save byeongsu-hong/566c26e5750f34afbb240f4a17f09b47 to your computer and use it in GitHub Desktop.
KAS Escape
This file contains 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 { | |
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