Hi there
In our CLOB on predicates in a few cases like fulfillment or cancelation of order, we should have the possibility to configure ScriptCallHandler
with inputs
and outputs
Here is the cancel_order
func on Rust language using Rust SDK
pub async fn cancel_order(
predicate: &Predicate,
wallet: &WalletUnlocked,
asset0: AssetId,
amount0: u64,
) -> Result<FuelCallResponse<()>, fuels::prelude::Error> {
let provider = wallet.provider().unwrap();
let inputs = predicate
.clone()
.set_provider(provider.clone())
.get_asset_inputs_for_amount(asset0, amount0, None)
.await
.unwrap();
let outputs = wallet.get_asset_outputs_for_amount(wallet.address(), asset0, 0);
println!("inputs = {:?}", inputs);
println!("outputs = {:?}", outputs);
let script_call = ScriptCallHandler::new(
vec![],
UnresolvedBytes::default(),
wallet.clone(),
provider.clone(),
Default::default(),
)
.with_inputs(inputs)
.with_outputs(outputs)
.tx_params(TxParameters::default().set_gas_price(1));
script_call.call().await
}
logs will be like that
alice_address = 0xccc4f9249536cf89ab0f31bb52fa06c00ea0387dcac5830924ecf56f2dded3a5
Predicate root = Bech32Address { hrp: "fuel", hash: c04e498ac26cbff0b93d9c218cf8bdc18e1190953ef5f3e5ace8146deded519c }
USDC AssetId (asset0) = 0x56fb8789a590ea9c12af6fe6dc2b43f347700b049d4f823fd4476c6f366af201
UNI AssetId (asset1) = 0x5381bbd1cff41519062c8531ec30e8ea1a2d752e59e4ac884068d3821e9f0093
inputs = [
ResourcePredicate {
resource: Coin(Coin {
amount: 1000000000,
block_created: 766024,
asset_id: 56fb8789a590ea9c12af6fe6dc2b43f347700b049d4f823fd4476c6f366af201,
utxo_id: UtxoId { tx_id: 2744628915b0d89ca8e79133a4598f72b32be9e884a723dad67a56c882da48ff, output_index: 2 },
maturity: 0,
owner: Bech32Address { hrp: "fuel", hash: c04e498ac26cbff0b93d9c218cf8bdc18e1190953ef5f3e5ace8146deded519c },
status: Unspent
}),
code: [...],
data: UnresolvedBytes { data: [] }
}
]
outputs = [
Coin {
to: ccc4f9249536cf89ab0f31bb52fa06c00ea0387dcac5830924ecf56f2dded3a5,
amount: 0,
asset_id: 56fb8789a590ea9c12af6fe6dc2b43f347700b049d4f823fd4476c6f366af201
},
Change {
to: ccc4f9249536cf89ab0f31bb52fa06c00ea0387dcac5830924ecf56f2dded3a5,
amount: 0,
asset_id: 56fb8789a590ea9c12af6fe6dc2b43f347700b049d4f823fd4476c6f366af201
}
]
In the predicate, this code is in charge of cancelation
let mut i = 0u8;
let inputs: u8 = input_count();
while i < inputs {
if input_owner(i).unwrap() == Address::from(MAKER) {
return true;
}
i += 1u8;
}
So, ts-sdk has func `` that can help us to make cancelation:
const cancelTx = await wallet.transfer(predicate.address, 0, token0.assetId, {
gasPrice: 1,
});
await cancelTx.waitForResult();
We did this script to test that
import BN from "../src/utils/BN";
import { TOKENS_BY_SYMBOL } from "../src/constants";
import { LimitOrderPredicateAbi__factory } from "../src/predicates";
import { Predicate, Provider, Wallet } from "fuels";
import { nodeUrl, privateKey } from "../src/config";
(async () => {
const token0 = TOKENS_BY_SYMBOL.USDC;
const amount0 = BN.parseUnits(20, token0.decimals);
const token1 = TOKENS_BY_SYMBOL.BTC;
const amount1 = BN.parseUnits(0.001, token1.decimals);
const exp = BN.parseUnits(1, 9 + token0.decimals - token1.decimals);
let price = amount1.times(exp).div(amount0);
const wallet = Wallet.fromPrivateKey(privateKey, nodeUrl);
// console.log(price.toString());
const configurableConstants = {
ASSET0: token0.assetId,
ASSET1: token1.assetId,
MAKER: wallet.address.toB256(),
PRICE: price.toFixed(0),
ASSET0_DECINALS: token0.decimals,
ASSET1_DECINALS: token1.decimals,
};
console.log(configurableConstants);
const predicate = new Predicate(
LimitOrderPredicateAbi__factory.bin,
LimitOrderPredicateAbi__factory.abi,
new Provider(nodeUrl),
configurableConstants
);
console.log(predicate.address.toB256());
const initialPredicateBalance = await predicate.getBalance(token0.assetId);
console.log("initialPredicateBalance", initialPredicateBalance.toString());
const depositTx = await wallet
.transfer(predicate.address, amount0.toFixed(0), token0.assetId, { gasPrice: 1 })
.catch((e) => console.error(`depositTx ${e}`));
await depositTx?.waitForResult();
//
const feeTx = await wallet
.transfer(predicate.address, 1, TOKENS_BY_SYMBOL.ETH.assetId, { gasPrice: 1 })
.catch((e) => console.error(`feeTx ${e}`));
await feeTx?.waitForResult();
const predicateBalances = await predicate.getBalances();
console.log(
"predicateBalances",
predicateBalances.map((v) => ({
amount: v.amount.toString(),
assetId: v.assetId.toString(),
}))
);
//---------------------
const cancelTx = await wallet.transfer(predicate.address, 0, token0.assetId, {
gasPrice: 1,
});
await cancelTx.waitForResult();
const finalPredicateBalance = await predicate.getBalances();
console.log(
"finalPredicateBalance",
finalPredicateBalance.map((v) => v.amount.toString())
);
})();
But this test fails with this error
/Users/alexey/projects/spark-ts-sdk/node_modules/graphql-request/src/index.ts:441
throw new ClientError(
^
ClientError: TransactionOutputCoinAssetIdNotFound(56fb8789a590ea9c12af6fe6dc2b43f347700b049d4f823fd4476c6f366af201): {"response":{"data":null,"errors":[{"message":"TransactionOutputCoinAssetIdNotFound(56fb8789a590ea9c12af6fe6dc2b43f347700b049d4f823fd4476c6f366af201)","locations":[{"line":2,"column":3}],"path":["dryRun"]}],"status":200,"headers":{}},"request":{"query":"mutation dryRun($encodedTransaction: HexString!, $utxoValidation: Boolean) {\n dryRun(tx: $encodedTransaction, utxoValidation: $utxoValidation) {\n ...receiptFragment\n }\n}\n\nfragment receiptFragment on Receipt {\n data\n rawPayload\n}","variables":{"encodedTransaction":"0x000000000000000000000000000000010000000005f5e1000000000000000000000000000000000400000000000000000000000000000001000000000000000200000000000000010000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000009835cda5c81ed1492fe4dc3696a7b39b6e94ac2c3ba4f739bafc69562061b31700000000000000042ce05bde9ada2d2c58b5eb9f08be34df19375d618626c324f75dfdbd226c8d8800000000000004300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057fe0ee890797038951426b07a7c0f16d135635e0bc27cae1461aae80ca6b7e6000000000000000056fb8789a590ea9c12af6fe6dc2b43f347700b049d4f823fd4476c6f366af20100000000000000032ce05bde9ada2d2c58b5eb9f08be34df19375d618626c324f75dfdbd226c8d88000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","utxoValidation":false}}}
at makeRequest (/Users/alexey/projects/spark-ts-sdk/node_modules/graphql-request/src/index.ts:441:11)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at async H.estimateTxDependencies (/Users/alexey/projects/spark-ts-sdk/node_modules/@fuel-ts/providers/src/provider.ts:387:39)
at async n.sendTransaction (/Users/alexey/projects/spark-ts-sdk/node_modules/@fuel-ts/wallet/src/base-unlocked-wallet.ts:85:5) {
response: {
data: null,
errors: [ [Object] ],
status: 200,
headers: Headers { [Symbol(map)]: [Object: null prototype] }
},
request: {
query: 'mutation dryRun($encodedTransaction: HexString!, $utxoValidation: Boolean) {\n' +
' dryRun(tx: $encodedTransaction, utxoValidation: $utxoValidation) {\n' +
' ...receiptFragment\n' +
' }\n' +
'}\n' +
'\n' +
'fragment receiptFragment on Receipt {\n' +
' data\n' +
' rawPayload\n' +
'}',
variables: {
encodedTransaction: '0x000000000000000000000000000000010000000005f5e1000000000000000000000000000000000400000000000000000000000000000001000000000000000200000000000000010000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000009835cda5c81ed1492fe4dc3696a7b39b6e94ac2c3ba4f739bafc69562061b31700000000000000042ce05bde9ada2d2c58b5eb9f08be34df19375d618626c324f75dfdbd226c8d8800000000000004300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057fe0ee890797038951426b07a7c0f16d135635e0bc27cae1461aae80ca6b7e6000000000000000056fb8789a590ea9c12af6fe6dc2b43f347700b049d4f823fd4476c6f366af20100000000000000032ce05bde9ada2d2c58b5eb9f08be34df19375d618626c324f75dfdbd226c8d88000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
utxoValidation: false
}
}
}