Skip to content

Commit dd79ed9

Browse files
authored
feat(ts-sdk): cw20 increase allowance (#3665)
~We can confirm cw20 increase allowance works by calling [`queryContractState`](https://github.com/unionlabs/union/pull/3665/files#diff-2c85a1ea1ce546d8f4f3a4e12ed73a56ade8759d8df4c263c0cdf5d7f48eda05R73-R104) and seeing `allowance` and `allowance_spender` updating.~ ~However, we can't merge this yet due to a pubkey decoding issue with `cosmjs`:~ ~This is fixable by updating our `cosmjs` patch. Once we do that we can then merge this~ proper patch has been applied to cosmjs. This PR is ready. The other updates in this PR are due to build step not working, so they were needed to make `bun run build` work.
2 parents fc1e34e + 8e4d18c commit dd79ed9

27 files changed

+1261
-89
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ evm/contracts/proto/** linguist-generated
1515
*.lockb binary diff=lockb
1616
*.zip filter=lfs diff=lfs merge=lfs -text
1717
site/public/union-logo.zip filter=lfs diff=lfs merge=lfs -text
18+
bun.lock linguist-language=JSON-with-Comments
1819
biome.json linguist-language=JSON-with-Comments
1920
knip.json linguist-language=JSON-with-Comments
2021
.vscode/*.json linguist-language=JSON-with-Comments

.vscode/settings.json

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
},
6161
"files.associations": {
6262
".envrc": "dotenv",
63+
"bun.lock": "jsonc",
6364
"biome.json": "jsonc",
6465
"*.css": "tailwindcss",
6566
".vscode/*.json": "jsonc"

flake.lock

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

treefmt.nix

+1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ in
135135
"*.jpg"
136136
"*.svg"
137137
"*.jpeg"
138+
"*.lock"
138139
".git/**"
139140
"*.woff2"
140141
"*.lockb"

typescript-sdk/.npmrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ package-lock=false
55
shell-emulator=true
66
git-tag-version=false
77
auto-install-peers=true
8-
node-options="--no-warnings NODE_NO_WARNINGS=1"
8+
node-options="--disable-warning=ExperimentalWarning NODE_NO_WARNINGS=1"
99

1010
@jsr:registry=https://npm.jsr.io

typescript-sdk/bun.lock

+846
Large diffs are not rendered by default.

typescript-sdk/bun.lockb

-156 KB
Binary file not shown.

typescript-sdk/package.json

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@unionlabs/client",
3-
"version": "0.0.56",
3+
"version": "0.0.57",
44
"homepage": "https://union.build",
55
"description": "Union Labs cross-chain transfers client",
66
"type": "module",
@@ -29,33 +29,35 @@
2929
"check-package": "bunx publint --strict && bunx @arethetypeswrong/cli@latest --pack --ignore-rules 'cjs-resolves-to-esm'"
3030
},
3131
"dependencies": {
32-
"@aptos-labs/ts-sdk": "^1.33.1",
32+
"@aptos-labs/ts-sdk": "^1.33.2",
3333
"@cosmjs/amino": "^0.33.0",
3434
"@cosmjs/cosmwasm-stargate": "0.33.0",
3535
"@cosmjs/proto-signing": "^0.33.0",
3636
"@cosmjs/stargate": "0.33.0",
3737
"@cosmjs/tendermint-rpc": "^0.33.0",
3838
"@scure/base": "^1.2.4",
39-
"gql.tada": "^1.8.10",
4039
"graphql-request": "^7.1.2",
4140
"neverthrow": "^8.1.1",
4241
"ofetch": "^1.4.1",
42+
"ox": "^0.6.9",
4343
"patch-package": "^8.0.0",
44-
"viem": "^2.22.13"
44+
"viem": "^2.22.21"
4545
},
4646
"devDependencies": {
47+
"gql.tada": "^1.8.10",
4748
"@total-typescript/ts-reset": "^0.6.1",
48-
"@types/bun": "^1.1.17",
49-
"@types/node": "^22.10.7",
49+
"@tsconfig/strictest": "^2.0.5",
50+
"@types/bun": "^1.2.2",
51+
"@types/node": "^22.13.1",
5052
"consola": "^3.4.0",
5153
"cosmjs-types": "^0.9.0",
52-
"jsr": "^0.13.2",
53-
"knip": "^5.42.2",
54-
"tsup": "^8.3.5",
54+
"jsr": "^0.13.3",
55+
"knip": "^5.43.6",
56+
"tsup": "^8.3.6",
5557
"tsx": "^4.19.2",
5658
"typescript": "^5.7.3",
5759
"vite-tsconfig-paths": "^5.1.4",
58-
"vitest": "^3.0.2"
60+
"vitest": "^3.0.5"
5961
},
6062
"repository": {
6163
"type": "git",

typescript-sdk/playground/babylon-to-holesky.ts

+5
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ if (quoteToken.isErr()) {
5959
process.exit(1)
6060
}
6161

62+
if (quoteToken.value.type === "NO_QUOTE_AVAILABLE") {
63+
consola.info("no quote token available")
64+
process.exit(1)
65+
}
66+
6267
consola.info("quote token", quoteToken.value)
6368

6469
if (!PRIVATE_KEY) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { fromHex, http, toHex } from "viem"
2+
import { parseArgs } from "node:util"
3+
import { consola } from "scripts/logger"
4+
import { createUnionClient, hexToBytes } from "#mod.ts"
5+
import {
6+
getChannelInfo,
7+
getQuoteToken,
8+
getRecommendedChannels
9+
} from "#query/offchain/ucs03-channels"
10+
import { DirectSecp256k1Wallet } from "@cosmjs/proto-signing"
11+
import { queryContractState } from "#query/on-chain"
12+
13+
// hack to encode bigints to json
14+
declare global {
15+
interface BigInt {
16+
toJSON: () => string
17+
}
18+
}
19+
20+
if (!BigInt.prototype.toJSON) {
21+
Object.defineProperty(BigInt.prototype, "toJSON", {
22+
value: function () {
23+
return this.toString()
24+
},
25+
writable: true,
26+
configurable: true
27+
})
28+
}
29+
// end hack
30+
31+
const cliArgs = parseArgs({
32+
args: process.argv.slice(2),
33+
options: {
34+
"private-key": { type: "string" },
35+
"estimate-gas": { type: "boolean", default: false }
36+
}
37+
})
38+
39+
const PRIVATE_KEY = cliArgs.values["private-key"]
40+
const WRASPPED_MUNO_DENOM_CW20 = "bbn1e9ycc775kxv7klq5eh9vznjslps3tqt3f2ttku8ptky9qqt6ecjqn570rp"
41+
const AMOUNT = 12n
42+
const RECEIVER = toHex("union1qcvavxpxw3t8d9j7mwaeq9wgytkf5vwpzq6pr4")
43+
const SOURCE_CHAIN_ID = "bbn-test-5"
44+
const DESTINATION_CHAIN_ID = "union-testnet-9"
45+
46+
const baseToken = toHex(WRASPPED_MUNO_DENOM_CW20)
47+
48+
const channels = await getRecommendedChannels()
49+
50+
const channel = getChannelInfo(SOURCE_CHAIN_ID, DESTINATION_CHAIN_ID, channels)
51+
if (channel === null) {
52+
consola.info("no channel found")
53+
process.exit(1)
54+
}
55+
56+
consola.info("channel", channel)
57+
58+
consola.info("base token", baseToken)
59+
60+
const quoteToken = await getQuoteToken(SOURCE_CHAIN_ID, baseToken, channel)
61+
if (quoteToken.isErr()) {
62+
consola.info("could not get quote token")
63+
consola.error(quoteToken.error)
64+
process.exit(1)
65+
}
66+
67+
if (quoteToken.value.type === "NO_QUOTE_AVAILABLE") {
68+
consola.error("No quote token available")
69+
process.exit(1)
70+
}
71+
consola.info("quote token", quoteToken.value)
72+
73+
if (!PRIVATE_KEY) {
74+
consola.error("no private key provided")
75+
process.exit(1)
76+
}
77+
78+
const unionClient = createUnionClient({
79+
chainId: SOURCE_CHAIN_ID,
80+
account: await DirectSecp256k1Wallet.fromKey(Uint8Array.from(hexToBytes(PRIVATE_KEY)), "bbn"),
81+
gasPrice: { amount: "0.025", denom: "ubbn" },
82+
transport: http("https://rpc.bbn-test-5.babylon.chain.kitchen")
83+
})
84+
85+
const CW20_TOKEN_MINTER = "bbn143365ksyxj0zxj26djqsjltscty75qdlpwry6yxhr8ckzhq92xas8pz8sn"
86+
87+
const allowanceParams = {
88+
contractAddress: WRASPPED_MUNO_DENOM_CW20,
89+
amount: AMOUNT,
90+
spender: CW20_TOKEN_MINTER
91+
}
92+
consola.info("allowance params", allowanceParams)
93+
94+
const approveResponse = await unionClient.cw20IncreaseAllowance(allowanceParams)
95+
consola.info("approval", approveResponse)
96+
97+
let contractSTate = await queryContractState({
98+
restUrl: "https://rest.bbn-test-5.babylon.chain.kitchen",
99+
contractAddress: WRASPPED_MUNO_DENOM_CW20
100+
})
101+
consola.log("contract state", contractSTate)
102+
103+
if (approveResponse.isErr()) {
104+
consola.error(approveResponse.error)
105+
process.exit(1)
106+
}
107+
108+
consola.info("approval tx hash", approveResponse.value)
109+
110+
const transfer = await unionClient.transferAsset({
111+
baseToken: WRASPPED_MUNO_DENOM_CW20,
112+
baseAmount: AMOUNT,
113+
quoteToken: quoteToken.value.quote_token,
114+
quoteAmount: AMOUNT,
115+
receiver: RECEIVER,
116+
sourceChannelId: channel.source_channel_id,
117+
ucs03address: fromHex(`0x${channel.source_port_id}`, "string")
118+
})
119+
120+
if (transfer.isErr()) {
121+
consola.error("transfer submission failed:", transfer.error)
122+
process.exit(1)
123+
}
124+
125+
consola.info("transfer tx hash", transfer.value)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env bun
2+
import { http } from "viem"
3+
import { parseArgs } from "node:util"
4+
import { consola } from "scripts/logger"
5+
import { hexToBytes } from "#convert.ts"
6+
import { createUnionClient } from "#mod.ts"
7+
import { raise } from "#utilities/index.ts"
8+
import { DirectSecp256k1Wallet } from "@cosmjs/proto-signing"
9+
10+
/* `bun playground/union-to-union.ts --private-key "..."` --estimate-gas */
11+
12+
const { values } = parseArgs({
13+
args: process.argv.slice(2),
14+
options: {
15+
"private-key": { type: "string" },
16+
"estimate-gas": { type: "boolean", default: false }
17+
}
18+
})
19+
20+
const PRIVATE_KEY = values["private-key"]
21+
if (!PRIVATE_KEY) raise("Private key not found")
22+
const ONLY_ESTIMATE_GAS = values["estimate-gas"] ?? false
23+
24+
const cosmosAccount = await DirectSecp256k1Wallet.fromKey(
25+
Uint8Array.from(hexToBytes(PRIVATE_KEY)),
26+
"union"
27+
)
28+
29+
const [account] = await cosmosAccount.getAccounts()
30+
if (!account) raise("no account found")
31+
32+
const client = createUnionClient({
33+
account: cosmosAccount,
34+
chainId: "union-testnet-9",
35+
transport: http("https://rpc.testnet-9.union.build")
36+
})
37+
38+
const transaction = await client.cw20IncreaseAllowance({
39+
account: cosmosAccount,
40+
amount: 50n,
41+
gasPrice: { amount: "0.0025", denom: "muno" },
42+
// CW20 Minter
43+
spender: "union16zul4t9a9lx5g900c2mrsdfxsnheg6gazsefsgpxhaektqnsxe4s4cl6ek",
44+
contractAddress: "union1vu9he2ldfl6uf4wh8h4llmt8n8pdtlgrvmkpdmqtzew4culkuv9sxxke4q"
45+
})
46+
47+
if (transaction.isErr()) {
48+
console.info("transaction failed")
49+
consola.error(transaction.error)
50+
process.exit(1)
51+
}
52+
53+
consola.info(transaction.value)
54+
process.exit(0)

typescript-sdk/playground/holesky-to-babylon.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { http } from "viem"
1+
import { getAddress, http } from "viem"
22
import { parseArgs } from "node:util"
33
import { consola } from "scripts/logger"
44
import { bech32AddressToHex, createUnionClient } from "#mod.ts"
@@ -59,16 +59,21 @@ if (quoteToken.isErr()) {
5959
process.exit(1)
6060
}
6161

62+
if (quoteToken.value.type === "NO_QUOTE_AVAILABLE") {
63+
consola.info("no quote token available")
64+
process.exit(1)
65+
}
66+
6267
consola.info("quote token", quoteToken.value)
6368

6469
const transferArgs = {
65-
baseToken: UBBN_DENOM,
70+
baseToken: getAddress(UBBN_DENOM),
6671
baseAmount: AMOUNT,
6772
quoteToken: quoteToken.value.quote_token,
6873
quoteAmount: AMOUNT,
6974
receiver: RECEIVER,
7075
sourceChannelId: channel.source_channel_id,
71-
ucs03address: `0x${channel.source_port_id}`
76+
ucs03address: getAddress(`0x${channel.source_port_id}`)
7277
}
7378

7479
consola.info("transfer args", transferArgs)

typescript-sdk/playground/holesky-to-sepolia.ts

+5
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ if (quoteToken.isErr()) {
4444
process.exit(1)
4545
}
4646

47+
if (quoteToken.value.type === "NO_QUOTE_AVAILABLE") {
48+
consola.info("no quote token available")
49+
process.exit(1)
50+
}
51+
4752
consola.info("quote token", quoteToken.value)
4853

4954
if (quoteToken.value.type === "NO_QUOTE_AVAILABLE") {

typescript-sdk/playground/holesky-to-stargaze.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { http } from "viem"
1+
import { getAddress, http } from "viem"
22
import { parseArgs } from "node:util"
33
import { consola } from "scripts/logger"
44
import { bech32AddressToHex, createUnionClient } from "#mod.ts"
@@ -67,13 +67,13 @@ if (quoteToken.value.type === "NO_QUOTE_AVAILABLE") {
6767
consola.info("quote token", quoteToken.value)
6868

6969
const transferArgs = {
70-
baseToken: STARS_DENOM,
70+
baseToken: getAddress(STARS_DENOM),
7171
baseAmount: AMOUNT,
7272
quoteToken: quoteToken.value.quote_token,
7373
quoteAmount: AMOUNT,
7474
receiver: RECEIVER,
7575
sourceChannelId: channel.source_channel_id,
76-
ucs03address: `0x${channel.source_port_id}`
76+
ucs03address: getAddress(`0x${channel.source_port_id}`)
7777
}
7878

7979
consola.info("transfer args", transferArgs)

typescript-sdk/playground/osmosis-to-holesky.ts

+5
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ if (quoteToken.isErr()) {
5959
process.exit(1)
6060
}
6161

62+
if (quoteToken.value.type === "NO_QUOTE_AVAILABLE") {
63+
consola.info("no quote token available")
64+
process.exit(1)
65+
}
66+
6267
consola.info("quote token", quoteToken.value)
6368

6469
if (!PRIVATE_KEY) {

typescript-sdk/playground/sepolia-to-holesky.ts

+5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ if (quoteToken.isErr()) {
4242
process.exit(1)
4343
}
4444

45+
if (quoteToken.value.type === "NO_QUOTE_AVAILABLE") {
46+
consola.info("no quote token available")
47+
process.exit(1)
48+
}
49+
4550
consola.info("quote token", quoteToken.value)
4651

4752
const transferArgs = {

typescript-sdk/playground/union-to-babylon.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const cliArgs = parseArgs({
3838
const PRIVATE_KEY = cliArgs.values["private-key"]
3939
const MUNO_DENOM = "muno"
4040
const AMOUNT = 12n
41-
const RECEIVER = toHex("bbn1xe0rnlh3u05qkwytkwmyzl86a0mvpwfxgf2t7u")
41+
const RECEIVER = toHex("bbn1qcvavxpxw3t8d9j7mwaeq9wgytkf5vwplf2cja")
4242
const SOURCE_CHAIN_ID = "union-testnet-9"
4343
const DESTINATION_CHAIN_ID = "bbn-test-5"
4444

typescript-sdk/scripts/publish.ts

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ async function main() {
6060
// revert changes
6161
await resetVersions()
6262
consola.info("Reset package.json version")
63+
return
6364
}
6465
}
6566

0 commit comments

Comments
 (0)