-
Notifications
You must be signed in to change notification settings - Fork 360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement determinstic contract addresses #1253
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
97f39df
Implement determinstic contract address generation
webmaster128 b968aae
Adapt length encoding
webmaster128 ae587c4
Make test addresses deterministic
webmaster128 64cf775
Update to use checksum instead of code_id
webmaster128 4de6c7e
Update contract_addresses.ts
webmaster128 09bdaed
Use toUint64
webmaster128 a408f1e
Fix wrong salt output
webmaster128 be0bd7a
Write intermediate data
webmaster128 bf5e854
Rename to instantiate2_addresses.ts and add to example runner
webmaster128 ee5429d
Move implementation to @cosmwasm/stargate
webmaster128 652c74d
Make msg a string | null
webmaster128 330e0bb
Remove msg argument from instantiate2Address and add tests
webmaster128 4287983
Add CHANGELOG entry for instantiate2Address
webmaster128 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)); |
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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", | ||
); | ||
} | ||
}); | ||
}); | ||
}); |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why msg is always set to null when instantiate2 while Wasmd v0.31.x include msgs when creating address?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See https://medium.com/cosmwasm/dev-note-3-limitations-of-instantiate2-and-how-to-deal-with-them-a3f946874230
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added #1398 for future readers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got it.
However, according to the link you provided, it seems that fix_msg should be null, not that instantiate msg should be null and current code is making instantiate msg to null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It refers to different aspects of the same thing. If
msg
is null or empty during address generation,fixed_msg
must be false in the actual instantiation.If
msg
is null/empty (during address generation) andfixed_msg = false
, then you can instantiate the contract with anymsg
you want without affecting the generated address.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, I am not familiar with wasmd, so I'm not sure how to use instantiate2.
If you have a chance, could you make a test code that compares the address obtained with instantiate2Address and the address of the contract instantiated with instantiate2 in the script/wasmd chain?
And thank you for your kind answers :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's still early for instantiate2 and not much resources are out there. Feel free to subscribe to #1399 to see
in CosmJS. The tests for this ticket will make a few things clearer I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A Pre-calculation tool here
https://blueprints.juno.giansalex.dev/#/contract/tools
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, nice! I strongly advise for removing the msg input field there. Nobody should need to use it.