mirror of
https://github.com/cosmos/cosmjs.git
synced 2025-03-10 21:49:15 +00:00
Merge pull request #1253 from cosmos/implement-determinstic-contract-address
Implement determinstic contract addresses
This commit is contained in:
commit
2b9b113f86
@ -45,9 +45,12 @@ and this project adheres to
|
||||
- @cosmjs/cosmwasm-stargate: Add constructors `CosmWasmClient.create` and
|
||||
`SigningCosmWasmClient.createWithSigner` to construct with a given Tendermint
|
||||
client ([#1376]).
|
||||
- @cosmjs/cosmwasm-stargate: Add `instantiate2Address` to pre-calculate
|
||||
addresses for Instantiate2 ([#1253]).
|
||||
- @cosmjs/stargate: Add `txIndex` to `DeliverTxResponse` and `IndexedTx`
|
||||
([#1361]).
|
||||
|
||||
[#1253]: https://github.com/cosmos/cosmjs/pull/1253
|
||||
[#1308]: https://github.com/cosmos/cosmjs/pull/1308
|
||||
[#1361]: https://github.com/cosmos/cosmjs/issues/1361
|
||||
[#1376]: https://github.com/cosmos/cosmjs/pull/1376
|
||||
|
62
packages/cli/examples/instantiate2_addresses.ts
Normal file
62
packages/cli/examples/instantiate2_addresses.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { fromBech32, fromHex, toBech32, toHex, toUtf8 } from "@cosmjs/encoding";
|
||||
import { _instantiate2AddressIntermediate } from "@cosmjs/cosmwasm-stargate";
|
||||
|
||||
function makeTestingAddress(length: number): string {
|
||||
let data = new Uint8Array(length);
|
||||
data.fill(0x99, 0);
|
||||
data.fill(0xaa, 5);
|
||||
data.fill(0xbb, 10);
|
||||
data.fill(0xcc, 15);
|
||||
data.fill(0xdd, 20);
|
||||
data.fill(0xee, 25);
|
||||
data.fill(0xff, 30);
|
||||
return toBech32("purple", data);
|
||||
}
|
||||
|
||||
let out: Array<any> = [];
|
||||
|
||||
const checksums = [
|
||||
fromHex("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5"),
|
||||
fromHex("1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b"),
|
||||
];
|
||||
const salts = [
|
||||
toUtf8("a"),
|
||||
fromHex(
|
||||
"AABBCCDDEEFFFFEEDDBBCCDDAA66551155aaaaBBCC787878789900AABBCCDDEEFFFFEEDDBBCCDDAA66551155aaaaBBCC787878789900aabbbbcc221100acadae",
|
||||
),
|
||||
];
|
||||
const msgs = [null, JSON.stringify({}), JSON.stringify({ some: 123, structure: { nested: ["ok", true] } })];
|
||||
|
||||
for (let checksum of checksums) {
|
||||
for (let creator of [makeTestingAddress(20), makeTestingAddress(32)]) {
|
||||
for (let salt of salts) {
|
||||
for (let msg of msgs) {
|
||||
const { key, addressData, address } = _instantiate2AddressIntermediate(
|
||||
checksum,
|
||||
creator,
|
||||
salt,
|
||||
msg,
|
||||
"purple",
|
||||
);
|
||||
out.push({
|
||||
in: {
|
||||
checksum: toHex(checksum),
|
||||
creator,
|
||||
creatorData: toHex(fromBech32(creator).data),
|
||||
salt: toHex(salt),
|
||||
msg,
|
||||
},
|
||||
intermediate: {
|
||||
key: toHex(key),
|
||||
addressData: toHex(addressData),
|
||||
},
|
||||
out: {
|
||||
address: address,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(out, undefined, 2));
|
@ -10,6 +10,7 @@ if [ -n "${SIMAPP44_ENABLED:-}" ]; then
|
||||
fi
|
||||
yarn node ./bin/cosmjs-cli --init examples/faucet_addresses.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmjs-cli --init examples/generate_address.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmjs-cli --init examples/instantiate2_addresses.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmjs-cli --init examples/local_faucet.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmjs-cli --init examples/mask.ts --code "process.exit(0)"
|
||||
yarn node ./bin/cosmjs-cli --init examples/multisig_address.ts --code "process.exit(0)"
|
||||
|
@ -1,5 +1,6 @@
|
||||
export { Code, CodeDetails, Contract, ContractCodeHistoryEntry, CosmWasmClient } from "./cosmwasmclient";
|
||||
export { fromBinary, toBinary } from "./encoding";
|
||||
export { _instantiate2AddressIntermediate, instantiate2Address } from "./instantiate2";
|
||||
export {
|
||||
cosmWasmTypes,
|
||||
createWasmAminoConverters,
|
||||
|
53
packages/cosmwasm-stargate/src/instantiate2.spec.ts
Normal file
53
packages/cosmwasm-stargate/src/instantiate2.spec.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { fromHex } from "@cosmjs/encoding";
|
||||
|
||||
import { instantiate2Address } from "./instantiate2";
|
||||
|
||||
describe("instantiate2", () => {
|
||||
describe("instantiate2Address", () => {
|
||||
it("works", () => {
|
||||
// Some entries from https://gist.github.com/webmaster128/e4d401d414bd0e7e6f70482f11877fbe
|
||||
{
|
||||
const checksum = fromHex("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5");
|
||||
const creator = "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py";
|
||||
const salt = fromHex("61");
|
||||
expect(instantiate2Address(checksum, creator, salt, "purple")).toEqual(
|
||||
"purple1t6r960j945lfv8mhl4mage2rg97w63xeynwrupum2s2l7em4lprs9ce5hk",
|
||||
);
|
||||
}
|
||||
{
|
||||
const checksum = fromHex("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5");
|
||||
const creator = "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py";
|
||||
const salt = fromHex(
|
||||
"aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
|
||||
);
|
||||
expect(instantiate2Address(checksum, creator, salt, "purple")).toEqual(
|
||||
"purple1jwzvvfyvpwchrccxl476pxf7c83qawsqv3f2820q0zyrav6eg4jqdcq7gc",
|
||||
);
|
||||
}
|
||||
{
|
||||
const checksum = fromHex("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5");
|
||||
const creator = "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m";
|
||||
const salt = fromHex("61");
|
||||
expect(instantiate2Address(checksum, creator, salt, "purple")).toEqual(
|
||||
"purple1juj7jn6j3k9h35euyhealntquc2zmzlxp2ek76jmtypkl4g4vrdsfwmwxk",
|
||||
);
|
||||
}
|
||||
{
|
||||
const checksum = fromHex("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5");
|
||||
const creator = "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m";
|
||||
const salt = fromHex("61");
|
||||
expect(instantiate2Address(checksum, creator, salt, "purple")).toEqual(
|
||||
"purple1juj7jn6j3k9h35euyhealntquc2zmzlxp2ek76jmtypkl4g4vrdsfwmwxk",
|
||||
);
|
||||
}
|
||||
{
|
||||
const checksum = fromHex("1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b");
|
||||
const creator = "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py";
|
||||
const salt = fromHex("61");
|
||||
expect(instantiate2Address(checksum, creator, salt, "purple")).toEqual(
|
||||
"purple1h9wyvusc6sy2p7fsgmez0dhvullpsyel7vq38k6d9fa7ehlv59qsvnyh36",
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
69
packages/cosmwasm-stargate/src/instantiate2.ts
Normal file
69
packages/cosmwasm-stargate/src/instantiate2.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Sha256, sha256 } from "@cosmjs/crypto";
|
||||
import { fromBech32, toAscii, toBech32, toUtf8 } from "@cosmjs/encoding";
|
||||
import { Uint64 } from "@cosmjs/math";
|
||||
import { assert } from "@cosmjs/utils";
|
||||
|
||||
/**
|
||||
* The "Basic Address" Hash from
|
||||
* https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/docs/architecture/adr-028-public-key-addresses.md
|
||||
*/
|
||||
function hash(type: string, key: Uint8Array): Uint8Array {
|
||||
return new Sha256(sha256(toAscii(type))).update(key).digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an integer [0, 2**64-1] and returns a one-byte encoding of it.
|
||||
*/
|
||||
function toUint64(int: number): Uint8Array {
|
||||
return Uint64.fromNumber(int).toBytesBigEndian();
|
||||
}
|
||||
|
||||
/**
|
||||
* Private function to export test vector data for https://github.com/cosmos/cosmjs/pull/1253.
|
||||
* Do not use in production code.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export function _instantiate2AddressIntermediate(
|
||||
checksum: Uint8Array,
|
||||
creator: string,
|
||||
salt: Uint8Array,
|
||||
msg: string | null,
|
||||
prefix: string,
|
||||
): { key: Uint8Array; addressData: Uint8Array; address: string } {
|
||||
assert(checksum.length === 32);
|
||||
const creatorData = fromBech32(creator).data;
|
||||
|
||||
const msgData = typeof msg === "string" ? toUtf8(msg) : new Uint8Array();
|
||||
|
||||
// Validate inputs
|
||||
if (salt.length < 1 || salt.length > 64) throw new Error("Salt must be between 1 and 64 bytes");
|
||||
|
||||
const key = new Uint8Array([
|
||||
...toAscii("wasm"),
|
||||
0x00,
|
||||
...toUint64(checksum.length),
|
||||
...checksum,
|
||||
...toUint64(creatorData.length),
|
||||
...creatorData,
|
||||
...toUint64(salt.length),
|
||||
...salt,
|
||||
...toUint64(msgData.length),
|
||||
...msgData,
|
||||
]);
|
||||
const addressData = hash("module", key);
|
||||
const address = toBech32(prefix, addressData);
|
||||
return { key, addressData, address };
|
||||
}
|
||||
|
||||
/**
|
||||
* Predictable address generation for the MsgInstantiateContract2
|
||||
* introduced with wasmd 0.29.
|
||||
*/
|
||||
export function instantiate2Address(
|
||||
checksum: Uint8Array,
|
||||
creator: string,
|
||||
salt: Uint8Array,
|
||||
prefix: string,
|
||||
): string {
|
||||
return _instantiate2AddressIntermediate(checksum, creator, salt, null, prefix).address;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user