Skip to content

Commit

Permalink
Update codebase to match new XDR schemas:
Browse files Browse the repository at this point in the history
 - function invocation now needs an InvokeContractArgs structure
 - signatureArgs was a 0-elem vec, now an ScVal w/ 0-elem vec
 - bodyType is gone
 - metaDataSizeBytes is gone
 - some minor test stuff has been tweaked for readability
  • Loading branch information
Shaptic committed Sep 11, 2023
1 parent c274198 commit 3b1eb16
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 103 deletions.
4 changes: 2 additions & 2 deletions src/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export function buildAuthEntry(envelope, signature, publicKey) {
address: new Address(publicKey).toScAddress(),
nonce: auth.nonce(),
signatureExpirationLedger: auth.signatureExpirationLedger(),
signatureArgs: [
signature: xdr.ScVal.scvVec([
nativeToScVal(
{
public_key: StrKey.decodeEd25519PublicKey(publicKey),
Expand All @@ -185,7 +185,7 @@ export function buildAuthEntry(envelope, signature, publicKey) {
}
}
)
]
])
})
)
});
Expand Down
30 changes: 14 additions & 16 deletions src/contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { StrKey } from './strkey';
* @param {string} contractId - ID of the contract (ex.
* `CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE`).
*/
// TODO: Support contract deployment, maybe?
export class Contract {
constructor(contractId) {
try {
Expand Down Expand Up @@ -49,18 +48,21 @@ export class Contract {
/**
* Returns an operation that will invoke this contract call.
*
* @param {string} method - name of the method to call
* @param {...xdr.ScVal} params - arguments to pass to the function call
* @returns {xdr.Operation} Build a InvokeHostFunctionOp operation to call the
* contract.
* @param {string} method name of the method to call
* @param {...xdr.ScVal} params arguments to pass to the function call
*
* @returns {xdr.Operation} an InvokeHostFunctionOp operation to call the
* contract with the given method and parameters
*/
call(method, ...params) {
return Operation.invokeHostFunction({
func: xdr.HostFunction.hostFunctionTypeInvokeContract([
this.address().toScVal(),
xdr.ScVal.scvSymbol(method),
...params
]),
func: xdr.HostFunction.hostFunctionTypeInvokeContract(
new xdr.InvokeContractArgs({
contractAddress: this.address().toScAddress(),
functionName: xdr.ScVal.scvSymbol(method),
args: params
})
),
auth: []
});
}
Expand All @@ -76,17 +78,13 @@ export class Contract {
getFootprint() {
return [
xdr.LedgerKey.contractCode(
new xdr.LedgerKeyContractCode({
hash: this._id,
bodyType: xdr.ContractEntryBodyType.dataEntry()
})
new xdr.LedgerKeyContractCode({ hash: this._id })
),
xdr.LedgerKey.contractData(
new xdr.LedgerKeyContractData({
contract: this.address().toScAddress(),
key: xdr.ScVal.scvLedgerKeyContractInstance(),
durability: xdr.ContractDataDurability.persistent(),
bodyType: xdr.ContractEntryBodyType.dataEntry()
durability: xdr.ContractDataDurability.persistent()
})
)
];
Expand Down
7 changes: 2 additions & 5 deletions src/sorobandata_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ export class SorobanDataBuilder {
footprint: new xdr.LedgerFootprint({ readOnly: [], readWrite: [] }),
instructions: 0,
readBytes: 0,
writeBytes: 0,
extendedMetaDataSizeBytes: 0
writeBytes: 0
}),
ext: new xdr.ExtensionPoint(0),
refundableFee: new xdr.Int64(0)
Expand Down Expand Up @@ -92,15 +91,13 @@ export class SorobanDataBuilder {
* @param {number} cpuInstrs number of CPU instructions
* @param {number} readBytes number of bytes being read
* @param {number} writeBytes number of bytes being written
* @param {number} metadataBytes number of extended metadata bytes
*
* @returns {SorobanDataBuilder}
*/
setResources(cpuInstrs, readBytes, writeBytes, metadataBytes) {
setResources(cpuInstrs, readBytes, writeBytes) {
this._data.resources().instructions(cpuInstrs);
this._data.resources().readBytes(readBytes);
this._data.resources().writeBytes(writeBytes);
this._data.resources().extendedMetaDataSizeBytes(metadataBytes);

return this;
}
Expand Down
17 changes: 8 additions & 9 deletions test/unit/auth_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('building authorization entries', function () {
const invocation = new xdr.SorobanAuthorizedInvocation({
function:
xdr.SorobanAuthorizedFunction.sorobanAuthorizedFunctionTypeContractFn(
new xdr.SorobanAuthorizedContractFunction({
new xdr.InvokeContractArgs({
contractAddress: new StellarBase.Address(contractId).toScAddress(),
functionName: 'hello',
args: [StellarBase.nativeToScVal('world!')]
Expand All @@ -28,12 +28,14 @@ describe('building authorization entries', function () {
);

let cred = entry.credentials().address();
let args = cred.signatureArgs().map((v) => StellarBase.scValToNative(v));
let sig = cred.signature();

expect(sig.switch().name).to.be.equal('scvVec');
const args = StellarBase.scValToNative(sig.vec()[0]);

expect(cred.signatureExpirationLedger()).to.equal(123);
expect(args.length).to.equal(1);
expect(
StellarBase.StrKey.encodeEd25519PublicKey(args[0]['public_key'])
StellarBase.StrKey.encodeEd25519PublicKey(args['public_key'])
).to.equal(kp.publicKey());
expect(entry.rootInvocation()).to.eql(invocation);

Expand All @@ -60,14 +62,11 @@ describe('building authorization entries', function () {
)
.then((entry) => {
let cred = entry.credentials().address();
let args = cred
.signatureArgs()
.map((v) => StellarBase.scValToNative(v));
let args = StellarBase.scValToNative(cred.signature().vec()[0]);

expect(cred.signatureExpirationLedger()).to.equal(123);
expect(args.length).to.equal(1);
expect(
StellarBase.StrKey.encodeEd25519PublicKey(args[0]['public_key'])
StellarBase.StrKey.encodeEd25519PublicKey(args['public_key'])
).to.equal(kp.publicKey());
expect(entry.rootInvocation()).to.eql(invocation);

Expand Down
49 changes: 28 additions & 21 deletions test/unit/contract_test.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,48 @@
const xdr = StellarBase.xdr;

const { Contract, xdr } = StellarBase;
const NULL_ADDRESS = 'CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM';

describe('Contract', function () {
describe('constructor', function () {
it('parses strkeys', function () {
let contractId =
'CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE';
let contract = new StellarBase.Contract(contractId);
let contract = new Contract(contractId);
expect(contract.contractId('strkey')).to.equal(contractId);
});

it('throws on obsolete hex ids', function () {
expect(() => {
new StellarBase.Contract('0'.repeat(63) + '1');
}).to.throw();
expect(() => new Contract('0'.repeat(63) + '1')).to.throw();
});

it('throws on invalid ids', function () {
expect(() => {
new StellarBase.Contract('foobar');
}).to.throw();
expect(() => new Contract('foobar')).to.throw();
});
});

describe('address', function () {
it('returns the contract address', function () {
let contract = new StellarBase.Contract(NULL_ADDRESS);
let contract = new Contract(NULL_ADDRESS);
expect(contract.address().toString()).to.equal(NULL_ADDRESS);
});
});

describe('getFootprint', function () {
it('includes the correct contract ledger keys', function () {
let contract = new StellarBase.Contract(NULL_ADDRESS);
let contract = new Contract(NULL_ADDRESS);
expect(contract.contractId()).to.equal(NULL_ADDRESS);

const actual = contract.getFootprint();
const expected = [
new xdr.LedgerKey.contractCode(
new xdr.LedgerKeyContractCode({
hash: StellarBase.StrKey.decodeContract(contract.contractId()),
bodyType: xdr.ContractEntryBodyType.dataEntry()
hash: StellarBase.StrKey.decodeContract(contract.contractId())
})
),
new xdr.LedgerKey.contractData(
new xdr.LedgerKeyContractData({
contract: contract.address().toScAddress(),
key: xdr.ScVal.scvLedgerKeyContractInstance(),
durability: xdr.ContractDataDurability.persistent(),
bodyType: xdr.ContractEntryBodyType.dataEntry()
durability: xdr.ContractDataDurability.persistent()
})
)
];
Expand All @@ -59,28 +52,42 @@ describe('Contract', function () {
});

describe('call', function () {
let call = new StellarBase.Contract(NULL_ADDRESS).call(
const contract = new Contract(NULL_ADDRESS);
let call = contract.call(
'method',
xdr.ScVal.scvU32(123)
StellarBase.nativeToScVal('arg!'),
StellarBase.nativeToScVal(2, { type: 'i32' }),
);

it('builds valid XDR', function () {
call.toXDR();
});

let args = call
.body()
.invokeHostFunctionOp()
.hostFunction()
.invokeContract();

it('passes the contract id as an ScAddress', function () {
expect(args[0]).to.deep.equal(
new StellarBase.Contract(NULL_ADDRESS).address().toScVal()
expect(args.contractAddress()).to.deep.equal(
new Contract(NULL_ADDRESS).address().toScAddress()
);
});

it('passes the method name as the second arg', function () {
expect(args[1]).to.deep.equal(xdr.ScVal.scvSymbol('method'));
expect(args.functionName()).to.deep.equal(xdr.ScVal.scvSymbol('method'));
});

it('passes all params after that', function () {
expect(args[2]).to.deep.equal(xdr.ScVal.scvU32(123));
expect(args.args()).to.deep.equal([
xdr.ScVal.scvString('arg!'),
xdr.ScVal.scvI32(2)
]);
});

it('works with no parameters', function () {
contract.call('empty').toXDR();
});
});
});
2 changes: 1 addition & 1 deletion test/unit/invocation_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function rk() {

function makeInvocation(contract, name, ...args) {
return xdr.SorobanAuthorizedFunction.sorobanAuthorizedFunctionTypeContractFn(
new xdr.SorobanAuthorizedContractFunction({
new xdr.InvokeContractArgs({
contractAddress: contract.address().toScAddress(),
functionName: name,
args: args.map(nativeToScVal)
Expand Down
16 changes: 11 additions & 5 deletions test/unit/operation_test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import BigNumber from 'bignumber.js';

import {
encodeMuxedAccountToAddress,
encodeMuxedAccount
} from '../../src/util/decode_encode_muxed_account.js';
const { encodeMuxedAccountToAddress, encodeMuxedAccount } = StellarBase;

describe('Operation', function () {
describe('.createAccount()', function () {
Expand Down Expand Up @@ -2018,8 +2015,17 @@ describe('Operation', function () {

describe('invokeHostFunction()', function () {
it('creates operation', function () {
const contractId =
'CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE';
const c = new StellarBase.Contract(contractId);
const op = StellarBase.Operation.invokeHostFunction({
func: StellarBase.xdr.HostFunction.hostFunctionTypeInvokeContract([]),
func: StellarBase.xdr.HostFunction.hostFunctionTypeInvokeContract(
new StellarBase.xdr.InvokeContractArgs({
contractAddress: c.address().toScAddress(),
functionName: 'hello',
args: [StellarBase.nativeToScVal('world')]
})
),
auth: []
});
var xdr = op.toXDR('hex');
Expand Down
19 changes: 5 additions & 14 deletions test/unit/sorobandata_builder_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,21 @@ let xdr = StellarBase.xdr;
let dataBuilder = StellarBase.SorobanDataBuilder;

describe('SorobanTransactionData can be built', function () {
const address = new StellarBase.Address(
StellarBase.Keypair.random().publicKey()
);
const contractId = 'CA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAXE';
const c = new StellarBase.Contract(contractId);

const sentinel = new xdr.SorobanTransactionData({
resources: new xdr.SorobanResources({
footprint: new xdr.LedgerFootprint({ readOnly: [], readWrite: [] }),
instructions: 1,
readBytes: 2,
writeBytes: 3,
extendedMetaDataSizeBytes: 4
writeBytes: 3
}),
ext: new xdr.ExtensionPoint(0),
refundableFee: new xdr.Int64(5)
});

const key = xdr.LedgerKey.contractData(
new xdr.LedgerKeyContractData({
contract: address.toScAddress(),
key: address.toScVal(),
durability: xdr.ContractDataDurability.persistent(),
bodyType: xdr.ContractEntryBodyType.dataEntry()
})
);
const key = c.getFootprint()[0];

it('constructs from xdr, base64, and nothing', function () {
new dataBuilder();
Expand All @@ -44,7 +35,7 @@ describe('SorobanTransactionData can be built', function () {

it('sets properties as expected', function () {
expect(
new dataBuilder().setResources(1, 2, 3, 4).setRefundableFee(5).build()
new dataBuilder().setResources(1, 2, 3).setRefundableFee(5).build()
).to.eql(sentinel);

// this isn't a valid param but we're just checking that setters work
Expand Down
Loading

0 comments on commit 3b1eb16

Please sign in to comment.