cosmic-interchain-cli
Version:
A command-line utility for Cosmic Wire's interchain messaging protocol
107 lines • 4.23 kB
JavaScript
import { GetPublicKeyCommand, KMSClient } from '@aws-sdk/client-kms';
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { input } from '@inquirer/prompts';
// @ts-ignore
import asn1 from 'asn1.js';
import { ethers } from 'ethers';
import { assert } from '@hyperlane-xyz/utils';
import { log, logBlue } from '../logger.js';
export async function getValidatorAddress({ context, accessKey, secretKey, region, bucket, keyId, }) {
if (!bucket && !keyId) {
throw new Error('Must provide either an S3 bucket or a KMS Key ID.');
}
// Query user for AWS parameters if not passed in or stored as .env variables
accessKey ||= await getAccessKeyId(context.skipConfirmation);
secretKey ||= await getSecretAccessKey(context.skipConfirmation);
region ||= await getRegion(context.skipConfirmation);
assert(accessKey, 'No access key ID set.');
assert(secretKey, 'No secret access key set.');
assert(region, 'No AWS region set.');
let validatorAddress;
if (bucket) {
validatorAddress = await getAddressFromBucket(bucket, accessKey, secretKey, region);
}
else {
validatorAddress = await getAddressFromKey(keyId, accessKey, secretKey, region);
}
logBlue('Validator address is: ');
log(validatorAddress);
}
/**
* Displays validator key address from
* validator announcement S3 bucket.
*/
async function getAddressFromBucket(bucket, accessKeyId, secretAccessKey, region) {
const s3Client = new S3Client({
region: region,
credentials: {
accessKeyId,
secretAccessKey,
},
});
const { Body } = await s3Client.send(new GetObjectCommand({
Bucket: bucket,
Key: 'announcement.json',
}));
if (Body) {
const announcement = JSON.parse(await Body?.transformToString());
return announcement['value']['validator'];
}
else {
throw new Error('Announcement file announcement.json not found in bucket');
}
}
/**
* Logs validator key address using AWS KMS key ID.
* Taken from github.com/tkporter/get-aws-kms-address/
*/
async function getAddressFromKey(keyId, accessKeyId, secretAccessKey, region) {
const client = new KMSClient({
region: region,
credentials: {
accessKeyId,
secretAccessKey,
},
});
const publicKeyResponse = await client.send(new GetPublicKeyCommand({ KeyId: keyId }));
return getEthereumAddress(Buffer.from(publicKeyResponse.PublicKey));
}
const EcdsaPubKey = asn1.define('EcdsaPubKey', function () {
this.seq().obj(this.key('algo').seq().obj(this.key('a').objid(), this.key('b').objid()), this.key('pubKey').bitstr());
});
function getEthereumAddress(publicKey) {
// The public key is ASN1 encoded in a format according to
// https://tools.ietf.org/html/rfc5480#section-2
const res = EcdsaPubKey.decode(publicKey, 'der');
let pubKeyBuffer = res.pubKey.data;
// The public key starts with a 0x04 prefix that needs to be removed
// more info: https://www.oreilly.com/library/view/mastering-ethereum/9781491971932/ch04.html
pubKeyBuffer = pubKeyBuffer.slice(1, pubKeyBuffer.length);
const address = ethers.utils.keccak256(pubKeyBuffer); // keccak256 hash of publicKey
return `0x${address.slice(-40)}`; // take last 20 bytes as ethereum address
}
async function getAccessKeyId(skipConfirmation) {
if (skipConfirmation)
throw new Error('No AWS access key ID set.');
else
return input({
message: 'Please enter AWS access key ID or use the AWS_ACCESS_KEY_ID environment variable.',
});
}
async function getSecretAccessKey(skipConfirmation) {
if (skipConfirmation)
throw new Error('No AWS secret access key set.');
else
return input({
message: 'Please enter AWS secret access key or use the AWS_SECRET_ACCESS_KEY environment variable.',
});
}
async function getRegion(skipConfirmation) {
if (skipConfirmation)
throw new Error('No AWS region set.');
else
return input({
message: 'Please enter AWS region or use the AWS_REGION environment variable.',
});
}
//# sourceMappingURL=address.js.map