The index value of the token used in the transaction within our system.
toChain
The nickName value of the Chain used in the transaction within our system.
toAddr
The target userβs address for this transaction.
slippage
The slippage information for this transaction. This value is in ten-thousandths, e.g., 10 (0.1%). When orderType = 1, the slippage is always 0.
execStrategy
Reserved field, pass an empty string by default.
extra
Transaction verification information; the accuracy of this value determines whether the transaction can be successful.
triggerPrice
Reserved field, pass "0" by default.
timeout
Reserved field, pass "0" by default.
channel
chainge
sourceCerts
Fields
Description
fromAmount
Transaction quantity.
fromIndex
The index value of the token used in the transaction within our system.
fromChain
The nickName value of the Chain used in the transaction within our system.
fromAddr
The current address of the user's connected kaspa wallet.
certHash
Transaction hash.
fromPublicKey
The publicKey of the current address.
signature
"123456"
Signature:
To obtain a correct interface signature, we need to follow these 5 steps:
Construct the body parameter object correctly according to the requirements.
Concatenate the parameters of the complete body parameter object, sorted alphabetically, using '&' as a separator. For example: channel=chainge&extra=1_3432345:3_2...
Prefix the string generated in step 2 with Address=...&{result of step 2}, for example: Address=kaspa:qzg4g46sd3hnax9fnjqdc2jfljs39f9ng00ntfhdz28rfwyc8adzuksnutgrq&channel=chainge&extra=1_3432345:3_2...
Apply keccak256 hashing to the result of step 3.
Sign the result of step 4 with the wallet.
get Signature examplesοΌ
sortParams= (params, evmAddress) => {let keys =Object.keys(params)if(!keys.length) returnundefined keys =keys.sort();constkeyValList= []for (constkeyof keys) {constval= params[key];if(val) {keyValList.push(`${key}=${val}`) } }constdata=keyValList.join('&')constraw=`Address=${evmAddress}&${data}`return raw}// step 1const bodyParams = {"sourceCerts":"7b2266726f6d416d6f756e74223a22313030303030303030222c2266726f6d496e646578223a2235222c2266726f6d436861696e223a224b4153222c2266726f6d41646472223a226b617370613a717a6734673436736433686e617839666e6a716463326a666c6a73333966396e6730306e746668647a323872667779633861647a756b736e7574677271222c226365727448617368223a2261626339323033383763613061386530393466393833336336306232666366613531386132316462643463613366393237313962313139376364623035313332222c2266726f6d5075626c69634b6579223a22303339313534353735303663366633653938613939633830646332613439666361313132613462333433646633356136656431323865333462383938336635613265222c227369676e6174757265223a22313233343536227d","orderType":"2","toIndex":"6","toChain":"KAS","toAddr":"kaspa:qzg4g46sd3hnax9fnjqdc2jfljs39f9ng00ntfhdz28rfwyc8adzuksnutgrq","slippage":"10","execStrategy":"","extra":"1_70105600;3_2;4_70035494;5_FSN","triggerPrice":"0","timeout":"0","channel":"chainge"}
// step 2 & setp3let raw =sortParams(bodyParams,'kaspa:qzg4g46sd3hnax9fnjqdc2jfljs39f9ng00ntfhdz28rfwyc8adzuksnutgrq') asstring;console.log(raw) // Address=kaspa:qzg4g46sd3hnax9fnjqdc2jfljs39f9ng00ntfhdz28rfwyc8adzuksnutgrq&channel=chainge&extra=1_70105600;3_2;4_70035494;5_FSN&orderType=2&slippage=10&sourceCerts=7b2266726f6d416d6f756e74223a22313030303030303030222c2266726f6d496e646578223a2235222c2266726f6d436861696e223a224b4153222c2266726f6d41646472223a226b617370613a717a6734673436736433686e617839666e6a716463326a666c6a73333966396e6730306e746668647a323872667779633861647a756b736e7574677271222c226365727448617368223a2261626339323033383763613061386530393466393833336336306232666366613531386132316462643463613366393237313962313139376364623035313332222c2266726f6d5075626c69634b6579223a22303339313534353735303663366633653938613939633830646332613439666361313132613462333433646633356136656431323865333462383938336635613265222c227369676e6174757265223a22313233343536227d&timeout=0&toAddr=kaspa:qzg4g46sd3hnax9fnjqdc2jfljs39f9ng00ntfhdz28rfwyc8adzuksnutgrq&toChain=KAS&toIndex=6&triggerPrice=0
// step4raw =keccak256(toHex(raw));console.log(raw) // 0x95d1a3c0495b8f6294ab53cdc5caf4c96eb78cffb1461e738edb2956e3ab800b// step5 Calling wallet message signing// Note: The signature should not include the prefix '0x'.let signature =wallet.signMessage(raw)
example:
This example is for demonstration purposes only.
// It's an example from CUSDT on KAS to PEPE on KAS
import BigNumber from 'bignumber.js';
import { MaxUint256, ethers, formatUnits, hexlify, parseUnits, toUtf8Bytes } from 'ethers'
import { getAggregateQuote, getAggregateSwap, getAssets, getBridgeQuote, getChain } from './api.js';
const fromAddress = 'kaspa:qzg4g46sd3hnax9fnjqdc2jfljs39f9ng00ntfhdz28rfwyc8adzuksnutgrq'
const publicKey = '03915457506c6f3e98a99c80dc2a49fca112a4b343df35a6ed128e34b8983f5a2e'
const channelFeeRate = '0'
// This information can be obtained through the getAssets APIs.
const USDTTokenForKAS = {
index: '5',
symbol: 'USDT',
decimals: 8,
address: 'CUSDT'
}
const PEPETokenForKAS = {
index: '103',
symbol: 'PEPE',
decimals: 8,
address: 'PEPE'
}
const fromAmount = '2'
const amount = parseUnits(fromAmount, USDTTokenForKAS.decimals).toString()
const params = {
fromAmount: amount,
fromTokenAddress: USDTTokenForKAS.address,
fromDecimal: USDTTokenForKAS.decimals,
fromChain: 'KAS',
toTokenAddress: PEPETokenForKAS.address,
toDecimal: PEPETokenForKAS.decimals,
toChain: 'KAS',
channelFeeRate: channelFeeRate,
}
// quote
const quoteResult = await getAggregateQuote(params)
if(quoteResult.code !== 0) return
const { chain, chainDecimal, outAmount, serviceFee, gasFee, slippage } = quoteResult.data
const receiveAmount = BigInt(outAmount) - BigInt(serviceFee) - BigInt(gasFee)
if(receiveAmount <= BigInt(0)) {
// The current quote amount cannot cover the fees. Please enter a larger amount.
return
}
// execution Chain Info
const executionChainObj = supportChainList.find((item) => item.network === chain)
// Calculate the value the user should receive.
const receiveAmountHr = formatUnits(receiveAmount, chainDecimal)
const receiveAmountForExtra = parseUnits(receiveAmountHr, BNBTokenForBnb.decimals).toString()
// Computed minimum, After calculating the minimum value, we need to convert it to the decimals of the target chain.
const miniAmount = BigNumber(receiveAmountHr).multipliedBy(BigNumber((1 - (slippage * 0.01)))).toString()
const miniAmountForExtra = parseUnits(miniAmount, BNBTokenForBnb.decimals).toString()
// 1_Expected value;2_Third party profit ratio;3_version;4_Mini Amount;5_Execution chain
const extra = `1_${receiveAmountForExtra};2_${channelFeeRate};3_2;4_${miniAmountForExtra};5_${executionChainObj.nickName}`
// You need to initiate a transaction to our minter through the wallet, and obtain the hash. This hash will be the transaction hash.
const tradeHash = ''
const sourceCertsObj = {
fromAmount: amount,
fromIndex: USDTTokenForKAS.index,
fromChain: 'KAS',
fromAddr: fromAddress,
certHash: tradeHash,
fromPublicKey: publicKey,
signature: "123456",
};
const sourceCertsStr = JSON.stringify(sourceCertsObj);
let sourceCertsHex = hexlify(toUtf8Bytes(sourceCertsStr));
sourceCertsHex = sourceCertsHex.substring(2);
// 7b2266726f6d416d6f756e74223a22323030303030303030222c2266726f6d496e646578223a2235222c2266726f6d436861696e223a224b4153222c2266726f6d41646472223a226b617370613a717a6734673436736433686e617839666e6a716463326a666c6a73333966396e6730306e746668647a323872667779633861647a756b736e7574677271222c226365727448617368223a2263393266633539323466363735323532303639363266353163373231663138653434663265663230393964363039363637396362366232616535343132633431222c2266726f6d5075626c69634b6579223a22303339313534353735303663366633653938613939633830646332613439666361313132613462333433646633356136656431323865333462383938336635613265222c227369676e6174757265223a22313233343536227d
const params = {
"sourceCerts": sourceCertsHex,
"orderType": "2",
"toIndex": "103",
"toChain": "KAS",
"toAddr": "kaspa:qzg4g46sd3hnax9fnjqdc2jfljs39f9ng00ntfhdz28rfwyc8adzuksnutgrq",
"slippage": "500",
"execStrategy": "",
"extra": "1_1724822492366;3_2;4_1638581367748;5_FSN",
"triggerPrice": "0",
"timeout": "0",
"channel": "chainge"
}
const freezeParams = Object.freeze(params)
let raw = sortParams(freezeParams, fromAddress)
raw = keccak256(hexlify(toUtf8Bytes(raw)))
// raw: 0xe9de17c0fc98f1ece312d1484f2b091efe63cbf13ef2a2b1bfc30da276194697
let signature = wallet.signMessage(raw)
const header = {
Address: fromAddress,
PublicKey: publicKey,
Chain: 'KAS',
Signature: signature
}
const response = await fetch('https://api2.chainge.finance/v1/submitOrder', {
method: "POST",
headers: {
"Content-Type": "application/json",
...header
},
body: JSON.stringify(params)
})
const result = await response.json()
NOTE:
We have three minter addresses; make sure to distinguish between them when using them.