-
Notifications
You must be signed in to change notification settings - Fork 58
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
Create NobleClient for interacting with noble #78
Merged
Merged
Changes from 2 commits
Commits
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
Large diffs are not rendered by default.
Oops, something went wrong.
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,117 @@ | ||
import { EncodeObject } from '@cosmjs/proto-signing'; | ||
import Long from 'long'; | ||
|
||
import { Network } from '../src/clients/constants'; | ||
import LocalWallet from '../src/clients/modules/local-wallet'; | ||
import { NobleClient } from '../src/clients/noble-client'; | ||
import { ValidatorClient } from '../src/clients/validator-client'; | ||
import { BECH32_PREFIX, NOBLE_BECH32_PREFIX } from '../src/lib/constants'; | ||
import { sleep } from '../src/lib/utils'; | ||
import { DYDX_TEST_MNEMONIC } from './constants'; | ||
|
||
async function test(): Promise<void> { | ||
const dydxClient = await ValidatorClient.connect( | ||
Network.testnet().validatorConfig, | ||
); | ||
|
||
const dydxWallet = await LocalWallet.fromMnemonic( | ||
DYDX_TEST_MNEMONIC, | ||
BECH32_PREFIX, | ||
); | ||
const nobleWallet = await LocalWallet.fromMnemonic( | ||
DYDX_TEST_MNEMONIC, | ||
NOBLE_BECH32_PREFIX, | ||
); | ||
|
||
const client = await NobleClient.connect('https://rpc.testnet.noble.strange.love', nobleWallet); | ||
|
||
if (nobleWallet.address === undefined || dydxWallet.address === undefined) { | ||
throw new Error('Wallet not found'); | ||
} | ||
|
||
// IBC to noble | ||
|
||
const ibcToNobleMsg: EncodeObject = { | ||
typeUrl: '/ibc.applications.transfer.v1.MsgTransfer', | ||
value: { | ||
sourcePort: 'transfer', | ||
sourceChannel: 'channel-0', | ||
token: { | ||
denom: | ||
'ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5', | ||
amount: '1000000', | ||
}, | ||
sender: dydxWallet.address, | ||
receiver: nobleWallet.address, | ||
timeoutTimestamp: Long.fromNumber( | ||
Math.floor(Date.now() / 1000) * 1e9 + 10 * 60 * 1e9, | ||
), | ||
}, | ||
}; | ||
|
||
const msgs = [ibcToNobleMsg]; | ||
const encodeObjects: Promise<EncodeObject[]> = new Promise((resolve) => resolve(msgs), | ||
); | ||
|
||
await dydxClient.post.send( | ||
dydxWallet, | ||
() => { | ||
return encodeObjects; | ||
}, | ||
false, | ||
undefined, | ||
undefined, | ||
); | ||
|
||
await sleep(30000); | ||
|
||
try { | ||
const coins = await client.getAccountBalances(nobleWallet.address); | ||
console.log('Balances'); | ||
console.log(JSON.stringify(coins)); | ||
|
||
// IBC from noble | ||
|
||
const ibcFromNobleMsg: EncodeObject = { | ||
typeUrl: '/ibc.applications.transfer.v1.MsgTransfer', | ||
value: { | ||
sourcePort: 'transfer', | ||
sourceChannel: 'channel-21', | ||
token: { | ||
denom: 'uusdc', | ||
amount: coins[0].amount, | ||
}, | ||
sender: nobleWallet.address, | ||
receiver: dydxWallet.address, | ||
timeoutTimestamp: Long.fromNumber( | ||
Math.floor(Date.now() / 1000) * 1e9 + 10 * 60 * 1e9, | ||
), | ||
}, | ||
}; | ||
const fee = await client.simulateTransaction([ibcFromNobleMsg]); | ||
|
||
ibcFromNobleMsg.value.token.amount = (parseInt(ibcFromNobleMsg.value.token.amount, 10) - | ||
Math.floor(parseInt(fee.amount[0].amount, 10) * 1.4)).toString(); | ||
|
||
await client.send([ibcFromNobleMsg]); | ||
} catch (error) { | ||
console.log(JSON.stringify(error.message)); | ||
} | ||
|
||
await sleep(30000); | ||
|
||
try { | ||
const coin = await client.getAccountBalance(nobleWallet.address, 'uusdc'); | ||
console.log('Balance'); | ||
console.log(JSON.stringify(coin)); | ||
} catch (error) { | ||
console.log(JSON.stringify(error.message)); | ||
} | ||
} | ||
|
||
test() | ||
.then(() => {}) | ||
.catch((error) => { | ||
console.log(error.message); | ||
console.log(error); | ||
}); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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,100 @@ | ||
import { EncodeObject, Registry, Coin } from '@cosmjs/proto-signing'; | ||
import { | ||
calculateFee, | ||
DeliverTxResponse, | ||
GasPrice, | ||
StdFee, | ||
defaultRegistryTypes, | ||
SigningStargateClient, | ||
} from '@cosmjs/stargate'; | ||
|
||
import { GAS_MULTIPLIER } from './constants'; | ||
import LocalWallet from './modules/local-wallet'; | ||
|
||
export class NobleClient { | ||
private stargateClient?: SigningStargateClient; | ||
private wallet?: LocalWallet; | ||
|
||
static async connect( | ||
restEndpoint: string, | ||
wallet: LocalWallet, | ||
): Promise<NobleClient> { | ||
const client = new NobleClient(); | ||
await client.initialize(restEndpoint, wallet); | ||
return client; | ||
} | ||
|
||
private async initialize( | ||
restEndpoint: string, | ||
wallet: LocalWallet, | ||
): Promise<void> { | ||
if (wallet?.offlineSigner === undefined) { | ||
throw new Error('Wallet signer not found'); | ||
} | ||
this.wallet = wallet; | ||
this.stargateClient = await SigningStargateClient.connectWithSigner( | ||
restEndpoint, | ||
wallet.offlineSigner, | ||
{ registry: new Registry(defaultRegistryTypes) }, | ||
); | ||
} | ||
|
||
getAccountBalances(address: string): Promise<readonly Coin[]> { | ||
if (!this.stargateClient) { | ||
throw new Error('stargateClient not initialized'); | ||
} | ||
return this.stargateClient.getAllBalances(address); | ||
} | ||
|
||
getAccountBalance(address: string, denom: string): Promise<Coin> { | ||
if (!this.stargateClient) { | ||
throw new Error('stargateClient not initialized'); | ||
} | ||
return this.stargateClient.getBalance(address, denom); | ||
} | ||
|
||
async send( | ||
messages: EncodeObject[], | ||
gasPrice: GasPrice = GasPrice.fromString('0.025uusdc'), | ||
memo?: string, | ||
): Promise<DeliverTxResponse> { | ||
if (!this.stargateClient) { | ||
throw new Error('NobleClient stargateClient not initialized'); | ||
} | ||
if (this.wallet?.address === undefined) { | ||
throw new Error('NobleClient wallet not initialized'); | ||
} | ||
// Simulate to get the gas estimate | ||
const fee = await this.simulateTransaction(messages, gasPrice, memo); | ||
|
||
// Sign and broadcast the transaction | ||
return this.stargateClient.signAndBroadcast( | ||
this.wallet.address, | ||
messages, | ||
fee, | ||
memo ?? '', | ||
); | ||
} | ||
|
||
async simulateTransaction( | ||
messages: readonly EncodeObject[], | ||
gasPrice: GasPrice = GasPrice.fromString('0.025uusdc'), | ||
memo?: string, | ||
): Promise<StdFee> { | ||
if (!this.stargateClient) { | ||
throw new Error('NobleClient stargateClient not initialized'); | ||
} | ||
if (this.wallet?.address === undefined) { | ||
throw new Error('NobleClient wallet not initialized'); | ||
} | ||
// Get simulated response | ||
const gasEstimate = await this.stargateClient.simulate( | ||
this.wallet?.address, | ||
messages, | ||
memo, | ||
); | ||
|
||
// Calculate and return the fee | ||
return calculateFee(Math.floor(gasEstimate * GAS_MULTIPLIER), gasPrice); | ||
} | ||
} |
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
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.
does this only accept squidPayloads or does it except generic payloads as well?
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 does specifically have to be a squid IBC payload as I parse the json here with that expectation. Similar to
withdrawToIBC
in this file