Skip to content
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

Added optional token bundling in change #525

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
34 changes: 34 additions & 0 deletions example/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export const TEST_EPOCH_PARAMS = {
"epoch_no": 364,
"min_fee_a": 44,
"min_fee_b": 155381,
"max_block_size": 90112,
"max_tx_size": 16384,
"max_bh_size": 1100,
"key_deposit": 2000000,
"pool_deposit": 500000000,
"max_epoch": 18,
"optimal_pool_count": 500,
"influence": 0.3,
"monetary_expand_rate": 0.003,
"treasury_growth_rate": 0.2,
"decentralisation": 0,
"extra_entropy": null,
"protocol_major": 6,
"protocol_minor": 0,
"min_utxo_value": 34482,
"min_pool_cost": 340000000,
"nonce": "d932efa15a43b37c7d3389bed5711b1ff4d1038ce9a864cb66d8ed0fe9129852",
"block_hash": "bc1d3072c7266c26c75eb5c9c1126dd2e509192e86d3350356154aede791a8bd",
"cost_models": "{\"PlutusV1\": {\"bData-cpu-arguments\": 150000, \"iData-cpu-arguments\": 150000, \"trace-cpu-arguments\": 150000, \"mkCons-cpu-arguments\": 150000, \"fstPair-cpu-arguments\": 150000, \"mapData-cpu-arguments\": 150000, \"sndPair-cpu-arguments\": 150000, \"unBData-cpu-arguments\": 150000, \"unIData-cpu-arguments\": 150000, \"bData-memory-arguments\": 32, \"cekLamCost-exBudgetCPU\": 29773, \"cekVarCost-exBudgetCPU\": 29773, \"headList-cpu-arguments\": 150000, \"iData-memory-arguments\": 32, \"listData-cpu-arguments\": 150000, \"nullList-cpu-arguments\": 150000, \"tailList-cpu-arguments\": 150000, \"trace-memory-arguments\": 32, \"mkCons-memory-arguments\": 32, \"mkNilData-cpu-arguments\": 150000, \"unMapData-cpu-arguments\": 150000, \"cekApplyCost-exBudgetCPU\": 29773, \"cekConstCost-exBudgetCPU\": 29773, \"cekDelayCost-exBudgetCPU\": 29773, \"cekForceCost-exBudgetCPU\": 29773, \"chooseData-cpu-arguments\": 150000, \"chooseList-cpu-arguments\": 150000, \"chooseUnit-cpu-arguments\": 150000, \"constrData-cpu-arguments\": 150000, \"fstPair-memory-arguments\": 32, \"ifThenElse-cpu-arguments\": 1, \"mapData-memory-arguments\": 32, \"mkPairData-cpu-arguments\": 150000, \"sndPair-memory-arguments\": 32, \"unBData-memory-arguments\": 32, \"unIData-memory-arguments\": 32, \"unListData-cpu-arguments\": 150000, \"cekLamCost-exBudgetMemory\": 100, \"cekVarCost-exBudgetMemory\": 100, \"headList-memory-arguments\": 32, \"listData-memory-arguments\": 32, \"nullList-memory-arguments\": 32, \"sha2_256-memory-arguments\": 4, \"sha3_256-memory-arguments\": 4, \"tailList-memory-arguments\": 32, \"cekBuiltinCost-exBudgetCPU\": 29773, \"cekStartupCost-exBudgetCPU\": 100, \"mkNilData-memory-arguments\": 32, \"unConstrData-cpu-arguments\": 150000, \"unMapData-memory-arguments\": 32, \"cekApplyCost-exBudgetMemory\": 100, \"cekConstCost-exBudgetMemory\": 100, \"cekDelayCost-exBudgetMemory\": 100, \"cekForceCost-exBudgetMemory\": 100, \"chooseData-memory-arguments\": 32, \"chooseList-memory-arguments\": 32, \"chooseUnit-memory-arguments\": 32, \"constrData-memory-arguments\": 32, \"equalsData-memory-arguments\": 1, \"ifThenElse-memory-arguments\": 1, \"mkNilPairData-cpu-arguments\": 150000, \"mkPairData-memory-arguments\": 32, \"unListData-memory-arguments\": 32, \"blake2b_256-memory-arguments\": 4, \"sha2_256-cpu-arguments-slope\": 29175, \"sha3_256-cpu-arguments-slope\": 82363, \"cekBuiltinCost-exBudgetMemory\": 100, \"cekStartupCost-exBudgetMemory\": 100, \"equalsString-memory-arguments\": 1, \"indexByteString-cpu-arguments\": 150000, \"unConstrData-memory-arguments\": 32, \"addInteger-cpu-arguments-slope\": 0, \"decodeUtf8-cpu-arguments-slope\": 1000, \"encodeUtf8-cpu-arguments-slope\": 1000, \"equalsData-cpu-arguments-slope\": 10000, \"equalsInteger-memory-arguments\": 1, \"mkNilPairData-memory-arguments\": 32, \"blake2b_256-cpu-arguments-slope\": 29175, \"appendString-cpu-arguments-slope\": 1000, \"equalsString-cpu-arguments-slope\": 1000, \"indexByteString-memory-arguments\": 1, \"lengthOfByteString-cpu-arguments\": 150000, \"lessThanInteger-memory-arguments\": 1, \"sha2_256-cpu-arguments-intercept\": 2477736, \"sha3_256-cpu-arguments-intercept\": 0, \"addInteger-memory-arguments-slope\": 1, \"decodeUtf8-memory-arguments-slope\": 8, \"encodeUtf8-memory-arguments-slope\": 8, \"equalsByteString-memory-arguments\": 1, \"equalsInteger-cpu-arguments-slope\": 1326, \"modInteger-cpu-arguments-constant\": 148000, \"modInteger-memory-arguments-slope\": 1, \"addInteger-cpu-arguments-intercept\": 197209, \"consByteString-cpu-arguments-slope\": 1000, \"decodeUtf8-cpu-arguments-intercept\": 150000, \"encodeUtf8-cpu-arguments-intercept\": 150000, \"equalsData-cpu-arguments-intercept\": 150000, \"appendString-memory-arguments-slope\": 1, \"blake2b_256-cpu-arguments-intercept\": 2477736, \"equalsString-cpu-arguments-constant\": 1000, \"lengthOfByteString-memory-arguments\": 4, \"lessThanByteString-memory-arguments\": 1, \"lessThanInteger-cpu-arguments-slope\": 497, \"modInteger-memory-arguments-minimum\": 1, \"multiplyInteger-cpu-arguments-slope\": 11218, \"sliceByteString-cpu-arguments-slope\": 5000, \"subtractInteger-cpu-arguments-slope\": 0, \"appendByteString-cpu-arguments-slope\": 621, \"appendString-cpu-arguments-intercept\": 150000, \"divideInteger-cpu-arguments-constant\": 148000, \"divideInteger-memory-arguments-slope\": 1, \"equalsByteString-cpu-arguments-slope\": 247, \"equalsString-cpu-arguments-intercept\": 150000, \"addInteger-memory-arguments-intercept\": 1, \"consByteString-memory-arguments-slope\": 1, \"decodeUtf8-memory-arguments-intercept\": 0, \"encodeUtf8-memory-arguments-intercept\": 0, \"equalsInteger-cpu-arguments-intercept\": 136542, \"modInteger-memory-arguments-intercept\": 0, \"consByteString-cpu-arguments-intercept\": 150000, \"divideInteger-memory-arguments-minimum\": 1, \"lessThanByteString-cpu-arguments-slope\": 248, \"lessThanEqualsInteger-memory-arguments\": 1, \"multiplyInteger-memory-arguments-slope\": 1, \"quotientInteger-cpu-arguments-constant\": 148000, \"quotientInteger-memory-arguments-slope\": 1, \"sliceByteString-memory-arguments-slope\": 1, \"subtractInteger-memory-arguments-slope\": 1, \"appendByteString-memory-arguments-slope\": 1, \"appendString-memory-arguments-intercept\": 0, \"equalsByteString-cpu-arguments-constant\": 150000, \"lessThanInteger-cpu-arguments-intercept\": 179690, \"multiplyInteger-cpu-arguments-intercept\": 61516, \"remainderInteger-cpu-arguments-constant\": 148000, \"remainderInteger-memory-arguments-slope\": 1, \"sliceByteString-cpu-arguments-intercept\": 150000, \"subtractInteger-cpu-arguments-intercept\": 197209, \"verifyEd25519Signature-memory-arguments\": 1, \"appendByteString-cpu-arguments-intercept\": 396231, \"divideInteger-memory-arguments-intercept\": 0, \"equalsByteString-cpu-arguments-intercept\": 112536, \"quotientInteger-memory-arguments-minimum\": 1, \"consByteString-memory-arguments-intercept\": 0, \"lessThanEqualsByteString-memory-arguments\": 1, \"lessThanEqualsInteger-cpu-arguments-slope\": 1366, \"remainderInteger-memory-arguments-minimum\": 1, \"lessThanByteString-cpu-arguments-intercept\": 103599, \"multiplyInteger-memory-arguments-intercept\": 0, \"quotientInteger-memory-arguments-intercept\": 0, \"sliceByteString-memory-arguments-intercept\": 0, \"subtractInteger-memory-arguments-intercept\": 1, \"verifyEd25519Signature-cpu-arguments-slope\": 1, \"appendByteString-memory-arguments-intercept\": 0, \"remainderInteger-memory-arguments-intercept\": 0, \"lessThanEqualsByteString-cpu-arguments-slope\": 248, \"lessThanEqualsInteger-cpu-arguments-intercept\": 145276, \"modInteger-cpu-arguments-model-arguments-slope\": 118, \"verifyEd25519Signature-cpu-arguments-intercept\": 3345831, \"lessThanEqualsByteString-cpu-arguments-intercept\": 103599, \"divideInteger-cpu-arguments-model-arguments-slope\": 118, \"modInteger-cpu-arguments-model-arguments-intercept\": 425507, \"quotientInteger-cpu-arguments-model-arguments-slope\": 118, \"remainderInteger-cpu-arguments-model-arguments-slope\": 118, \"divideInteger-cpu-arguments-model-arguments-intercept\": 425507, \"quotientInteger-cpu-arguments-model-arguments-intercept\": 425507, \"remainderInteger-cpu-arguments-model-arguments-intercept\": 425507}}",
"price_mem": 0.0577,
"price_step": 0.0000721,
"max_tx_ex_mem": 14000000,
"max_tx_ex_steps": 10000000000,
"max_block_ex_mem": 62000000,
"max_block_ex_steps": 40000000000,
"max_val_size": 5000,
"collateral_percent": 150,
"max_collateral_inputs": 3,
"coins_per_utxo_size": 34482
}
140 changes: 104 additions & 36 deletions example/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
import CardanoWasm = require('rust-lib')
import wasm = require('rust-lib')
import { expect } from 'chai'
import 'mocha';
import { mnemonicToEntropy } from 'bip39';
import { initTransactionBuilder, toHex } from './index';
import { TEST_EPOCH_PARAMS } from './consts';

function harden(num: number): number {
function harden (num: number): number {
return 0x80000000 + num;
}

// Purpose derivation (See BIP43)
enum Purpose {
CIP1852=1852, // see CIP 1852
CIP1852 = 1852, // see CIP 1852
}

// Cardano coin type (SLIP 44)
enum CoinTypes {
CARDANO=1815,
CARDANO = 1815,
}

enum ChainDerivation {
EXTERNAL=0, // from BIP44
INTERNAL=1, // from BIP44
CHIMERIC=2, // from CIP1852
EXTERNAL = 0, // from BIP44
INTERNAL = 1, // from BIP44
CHIMERIC = 2, // from CIP1852
}

function getCip1852Account(): CardanoWasm.Bip32PrivateKey {
function getCip1852Account (): wasm.Bip32PrivateKey {
const entropy = mnemonicToEntropy(
[ "test", "walk", "nut", "penalty", "hip", "pave", "soap", "entry", "language", "right", "filter", "choice" ].join(' ')
["test", "walk", "nut", "penalty", "hip", "pave", "soap", "entry", "language", "right", "filter", "choice"].join(' ')
)
const rootKey = CardanoWasm.Bip32PrivateKey.from_bip39_entropy(
const rootKey = wasm.Bip32PrivateKey.from_bip39_entropy(
Buffer.from(entropy, 'hex'),
Buffer.from(''),
);
Expand All @@ -37,6 +39,7 @@ function getCip1852Account(): CardanoWasm.Bip32PrivateKey {
.derive(harden(0)); // account #0
}


describe('Addresses', () => {
it('derive base address', () => {
// from address test vectors
Expand All @@ -52,65 +55,130 @@ describe('Addresses', () => {
.derive(0)
.to_public();

const baseAddr = CardanoWasm.BaseAddress.new(
0,
CardanoWasm.StakeCredential.from_keyhash(utxoPubKey.to_raw_key().hash()),
CardanoWasm.StakeCredential.from_keyhash(stakeKey.to_raw_key().hash()),
const baseAddr = wasm.BaseAddress.new(
1,
wasm.StakeCredential.from_keyhash(utxoPubKey.to_raw_key().hash()),
wasm.StakeCredential.from_keyhash(stakeKey.to_raw_key().hash()),
);

expect(baseAddr.to_address().to_bech32()).to.eq('addr1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj83ws8lhrn648jjxtwqcyl47r');
expect(baseAddr.to_address().to_bech32())
.to.eq('addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj83ws8lhrn648jjxtwqfjkjv7');
})
});

describe('Transactions', () => {
it('create transaction', () => {
const txBuilder = CardanoWasm.TransactionBuilder.new(
// all of these are taken from the mainnet genesis settings
CardanoWasm.LinearFee.new(CardanoWasm.BigNum.from_str('44'), CardanoWasm.BigNum.from_str('155381')),
CardanoWasm.BigNum.from_str('1000000'),
CardanoWasm.BigNum.from_str('500000000'),
CardanoWasm.BigNum.from_str('2000000')
it('creates a bundled nft transaction', () => {
const txBuilder = initTransactionBuilder(TEST_EPOCH_PARAMS)

const address = wasm.ByronAddress.from_base58("Ae2tdPwUPEZLs4HtbuNey7tK4hTKrwNwYtGqp7bDfCy2WdR3P6735W5Yfpe");
txBuilder.add_bootstrap_input(
address,
wasm.TransactionInput.new(
wasm.TransactionHash.from_bytes(
Buffer.from("488afed67b342d41ec08561258e210352fba2ac030c98a8199bc22ec7a27ccf1", "hex"),
),
0, // index
),
wasm.Value.from_json(JSON.stringify({
coin: '300000000',
multiasset: {
'7cfcafe81fc8f62e618cef2a18ec2fa68e1c6c6f8a1ecf6a19f89188': {
[toHex('nft 01')]: '1',
[toHex('nft 02')]: '1',
[toHex('nft 03')]: '1',
[toHex('nft 04')]: '1',
[toHex('nft 05')]: '1',
[toHex('nft 06')]: '1',
[toHex('nft 07')]: '1',
[toHex('nft 08')]: '1',
[toHex('nft 09')]: '1',
[toHex('nft 10')]: '1',
}
}
}))
);

const address = CardanoWasm.ByronAddress.from_base58("Ae2tdPwUPEZLs4HtbuNey7tK4hTKrwNwYtGqp7bDfCy2WdR3P6735W5Yfpe");
txBuilder.add_output(wasm.TransactionOutput.new(
address.to_address(),
wasm.Value.from_json(JSON.stringify({ coin: '10000000' }))
))

txBuilder.set_ttl(410021);

// calculate the min fee required and send any change to an address
const changeAddress = wasm.ByronAddress.from_base58("Ae2tdPwUPEYxiWbAt3hUCJsZ9knze88qNhuTQ1MGCKqsVFo5ddNyoTDBymr").to_address()
txBuilder.add_bundled_change_if_needed(changeAddress, 2)

const txBody = txBuilder.build();
const txHash = wasm.hash_transaction(txBody);
const witnesses = wasm.TransactionWitnessSet.new();
const bootstrapWitnesses = wasm.BootstrapWitnesses.new();
const bootstrapWitness = wasm.make_icarus_bootstrap_witness(txHash, address, getCip1852Account());
bootstrapWitnesses.add(bootstrapWitness);
witnesses.set_bootstraps(bootstrapWitnesses);
const transaction = wasm.Transaction.new(
txBody,
witnesses,
undefined, // transaction metadata
);

console.log(`Change output was split into ${txBody.outputs().len() - 1}`)
for (let i = 0; i < txBody.outputs().len(); i++) {
console.log(i, txBody.outputs().get(i).amount().to_js_value())
}
expect(txBody.outputs().len() - 1).equal(6)

const txHex = toHex(transaction.to_bytes());
console.log(txHex);
})

it('creates a transaction', () => {
const txBuilder = initTransactionBuilder(TEST_EPOCH_PARAMS)

const address = wasm.ByronAddress.from_base58("Ae2tdPwUPEZLs4HtbuNey7tK4hTKrwNwYtGqp7bDfCy2WdR3P6735W5Yfpe");
txBuilder.add_bootstrap_input(
address,
CardanoWasm.TransactionInput.new(
CardanoWasm.TransactionHash.from_bytes(
wasm.TransactionInput.new(
wasm.TransactionHash.from_bytes(
Buffer.from("488afed67b342d41ec08561258e210352fba2ac030c98a8199bc22ec7a27ccf1", "hex"),
),
0, // index
),
CardanoWasm.BigNum.from_str('3000000')
wasm.Value.from_json(JSON.stringify({
coin: '10000000'
}))
);

txBuilder.add_output(
CardanoWasm.TransactionOutput.new(
wasm.TransactionOutput.new(
address.to_address(),
// we can construct BigNum (Coin) from both a js BigInt (here) or from a string (below in fee)
CardanoWasm.BigNum.from_str("1000000"),
wasm.Value.from_json(JSON.stringify({
coin: '2000000',
}))
),
);

txBuilder.set_ttl(410021);

// calculate the min fee required and send any change to an address
txBuilder.add_change_if_needed(CardanoWasm.ByronAddress.from_base58("Ae2tdPwUPEYxiWbAt3hUCJsZ9knze88qNhuTQ1MGCKqsVFo5ddNyoTDBymr").to_address())
const changeAddress = wasm.ByronAddress.from_base58("Ae2tdPwUPEYxiWbAt3hUCJsZ9knze88qNhuTQ1MGCKqsVFo5ddNyoTDBymr").to_address()
txBuilder.add_bundled_change_if_needed(changeAddress, 2)

const txBody = txBuilder.build();
const txHash = CardanoWasm.hash_transaction(txBody);
const witnesses = CardanoWasm.TransactionWitnessSet.new();
const bootstrapWitnesses = CardanoWasm.BootstrapWitnesses.new();
const bootstrapWitness = CardanoWasm.make_icarus_bootstrap_witness(txHash,address,getCip1852Account());
const txHash = wasm.hash_transaction(txBody);
const witnesses = wasm.TransactionWitnessSet.new();
const bootstrapWitnesses = wasm.BootstrapWitnesses.new();
const bootstrapWitness = wasm.make_icarus_bootstrap_witness(txHash, address, getCip1852Account());
bootstrapWitnesses.add(bootstrapWitness);
witnesses.set_bootstraps(bootstrapWitnesses);
const transaction = CardanoWasm.Transaction.new(
const transaction = wasm.Transaction.new(
txBody,
witnesses,
undefined, // transaction metadata
);

const txHex = Buffer.from(transaction.to_bytes()).toString("hex");
const txHex = toHex(transaction.to_bytes());
console.log(txHex);
})

});
48 changes: 42 additions & 6 deletions example/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,54 @@

import wasm = require('rust-lib')

export const toBigNum = (x: number | BigInt): wasm.BigNum => wasm.BigNum.from_str(x.toString())
export const toHex = (bytes: any, format?: BufferEncoding) => Buffer.from(bytes, format).toString('hex')

export type EpochParams = {
min_fee_a: number,
min_fee_b: number,
pool_deposit: number,
key_deposit: number,
max_val_size: number,
max_tx_size: number,
coins_per_utxo_size: number,
}

export function initTransactionBuilder (epochParams: EpochParams): wasm.TransactionBuilder {
const {
min_fee_a,
min_fee_b,
pool_deposit,
key_deposit,
max_val_size,
max_tx_size,
coins_per_utxo_size
} = epochParams

const config = wasm.TransactionBuilderConfigBuilder.new()
.fee_algo(wasm.LinearFee.new(toBigNum(min_fee_a), toBigNum(min_fee_b)))
.pool_deposit(toBigNum(pool_deposit))
.key_deposit(toBigNum(key_deposit))
.max_value_size(max_val_size)
.max_tx_size(max_tx_size)
.prefer_pure_change(true)
.coins_per_utxo_word(toBigNum(coins_per_utxo_size))

return wasm.TransactionBuilder.new(config.build())
}

const metadata = wasm.TransactionMetadatum.from_bytes(
Buffer.from("a200a16e4c615f52657073697374616e634568576173206865726501a56743686f6963657384a36b43616e6469646174654964782461616139353033612d366663352d343665612d396161302d62346339306633363161346368566f746552616e6b016a566f746557656967687401a36b43616e6469646174654964782438643634396331322d393336652d343662652d623635612d63313766333066353935373468566f746552616e6b026a566f746557656967687401a36b43616e6469646174654964782438316365376638652d393463332d343833352d393166632d32313436643531666131666368566f746552616e6b006a566f746557656967687400a36b43616e6469646174654964782434303735343061612d353862352d343063612d623438342d66343030343065623239393068566f746552616e6b036a566f746557656967687401694e6574776f726b49646f5468655265616c4164616d4465616e6a4f626a656374547970656a566f746542616c6c6f746a50726f706f73616c4964782438303036346332382d316230332d346631632d616266302d63613863356139386435623967566f7465724964782464393930613165382d636239302d346635392d623563662d613862353963396261386165", "hex")
);
const map = metadata.as_map();
const keys = map.keys();
for (let i = 0; i < keys.len(); i++) {
const val = keys.get(i);
console.log(Buffer.from(val.to_bytes()).toString('hex'));
console.log(toHex(val.to_bytes()));
}

const addr = wasm.Address.from_bech32('addr1qxy657awttf5avs2629f4hs6k5ulhw8f27akv30yws622dudj86zwkwhv3yjky5ntrmhcln5yxc05rcq0lhs8l78vd3qhc5eak');
console.log(Buffer.from(addr.to_bytes()).toString('hex'));
console.log(toHex(addr.to_bytes()));
// const addr = wasm.Address.from_bytes(Buffer.from('615c619e192407b2e972f04f0dda7c52aa8013d45ee7ba69d57041cad0', 'hex'));
// console.log(addr.to_bech32());

Expand All @@ -22,10 +58,10 @@ console.log(Buffer.from(addr.to_bytes()).toString('hex'));
// console.log(wasm.ByronAddress.is_valid('Ae2tdPwUPEZFAi4DxQaXeW9HAXYjdfvMWLgNXCJVjvweygZkAUiLjRwGfPr'));
// console.log(wasm.ByronAddress.is_valid('Ae2tdPwUPEZ3MHKkpT5Bpj549vrRH7nBqYjNXnCV8G2Bc2YxNcGHEa8ykDp'));
// const addr = wasm.Address.from_bech32(
// Buffer.from(
// 'stake1uy5mdzcepk905jj5vqzgyxly57ldhzegugzp9y7fruc6d5sqapp2u',
// 'hex'
// ),
// Buffer.from(
// 'stake1uy5mdzcepk905jj5vqzgyxly57ldhzegugzp9y7fruc6d5sqapp2u',
// 'hex'
// ),
// );

// const enterpriseAddr = wasm.EnterpriseAddress.new(
Expand Down
Loading