Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
59c932f
Merge pull request #594 from multiversx/main
danielailie Apr 14, 2025
59fe539
Add multisig transaction factory
danielailie Apr 14, 2025
d9fd92a
Remove unused variables
danielailie Apr 15, 2025
3390616
remove empty comment
danielailie Apr 15, 2025
0f55847
Remove unused resources
danielailie Apr 15, 2025
14bf65e
Add multisig controller
danielailie Apr 15, 2025
a215c4f
Add parser
danielailie Apr 15, 2025
93569cd
Update resources
danielailie Apr 15, 2025
dbd3944
Bump version
danielailie Apr 15, 2025
925f5d7
Update resources
danielailie Apr 15, 2025
1b0782d
Bump version
danielailie Apr 15, 2025
baa7983
Add multisig controller
danielailie Apr 15, 2025
1fa8802
Bump version
danielailie Apr 16, 2025
067c7e2
Add methods to export multisig controller and factopry on entrypoints
danielailie Apr 16, 2025
02828b5
Fix deploy transaction
danielailie Apr 16, 2025
bd6c6c1
Merge branch 'TOOL-329-add-mustisig-factory' into TOOL-329-add-mustis…
danielailie Apr 16, 2025
7582add
Merge branch 'TOOL-329-add-mustisig-controller' into TOOL-552-export-…
danielailie Apr 16, 2025
2bcc31c
Add getPendingActionFullInfo
danielailie Apr 17, 2025
be6ca32
Add getPendingActionFullInfo
danielailie Apr 17, 2025
b3f7d9b
bump version
danielailie Apr 17, 2025
79c8bb4
remove console.log
danielailie Apr 17, 2025
f615bc5
Merge branch 'TOOL-329-add-mustisig-controller' into TOOL-552-export-…
danielailie Apr 17, 2025
9243f44
Remove IAbi and use concret implementation
danielailie Apr 22, 2025
2e3f936
Refector ProposeTransferExecuteContractInput
danielailie Apr 22, 2025
18e42ec
Extract mapTokenPayment
danielailie Apr 22, 2025
8a4ea68
Fix build
danielailie Apr 22, 2025
6c07b4c
Remove extra characters
danielailie Apr 22, 2025
7b02b90
Update getAllBoardMembers mapping
danielailie Apr 24, 2025
0e2b460
Update getAllBoardMembers mapping
danielailie Apr 24, 2025
5fdef5a
Bump Version
danielailie Apr 24, 2025
e74c7ed
Update map tokenPayments
danielailie Apr 29, 2025
721eb9d
Increase sleep for integration tests
danielailie Apr 29, 2025
ee573c0
Merge branch 'feat/next' into MergeInNext
danielailie Apr 29, 2025
442417c
Merge pull request #601 from multiversx/MergeInNext
danielailie Apr 29, 2025
8194fc4
merge
danielailie Apr 29, 2025
683597e
Merge pull request #595 from multiversx/TOOL-329-add-mustisig-factory
danielailie Apr 29, 2025
5bbd6d7
Merge branch 'feat/next' into TOOL-329-add-mustisig-controller
danielailie Apr 29, 2025
6ff152e
Update multisig parser
danielailie May 5, 2025
df6244f
merge main
danielailie May 5, 2025
132da8f
Merge pull request #606 from multiversx/MergeMainInFeatNext
danielailie May 5, 2025
8fcba28
Merge feat next
danielailie May 5, 2025
27246b5
Pass abi when create multisig via entrypoint
danielailie May 5, 2025
ce51f86
Merge multisig controller
danielailie May 5, 2025
dcffb10
Bump version
danielailie May 5, 2025
71ab609
Make abi mandatory
danielailie May 5, 2025
124eb90
Clean-up parser
danielailie May 6, 2025
53c3069
Rename function
danielailie May 6, 2025
805f71d
Comments update
danielailie May 6, 2025
c17402c
Fix build
danielailie May 6, 2025
fac8604
Merge pull request #597 from multiversx/TOOL-329-add-mustisig-controller
danielailie May 6, 2025
1583368
Merge branch 'feat/next' into TOOL-552-export-multisig-factory-and-mu…
danielailie May 6, 2025
fb8248a
Fix build
danielailie May 6, 2025
629d8ba
Merge pull request #598 from multiversx/TOOL-552-export-multisig-fact…
danielailie May 6, 2025
3fdb8a8
Clean-up multisig controller and factory
danielailie May 6, 2025
99804cc
Fix deploy and upgrade from source
danielailie May 7, 2025
034d18c
Add await and parse methods
danielailie May 7, 2025
11d3ae8
fix test
danielailie May 7, 2025
3ef9f22
Merge pull request #607 from multiversx/UpdateToComposition
danielailie May 7, 2025
17942d3
Update types on gasLimit and address
danielailie May 7, 2025
386ec8d
Update to use optGasLimit when passed
danielailie May 7, 2025
695f9b0
Bump version
danielailie May 7, 2025
034cbee
Update factory
danielailie May 7, 2025
996dacd
Merge pull request #608 from multiversx/TOOL-568-update-types-on-mult…
danielailie May 7, 2025
60d15bf
Delete unused files
danielailie May 7, 2025
a80ddf4
Merge pull request #609 from multiversx/TOOL-569-clean-up-unused-files
danielailie May 7, 2025
915ec8b
Merge branch 'main' into merge-main-in-feat-12-05
popenta May 12, 2025
82437ef
Merge pull request #612 from multiversx/merge-main-in-feat-12-05
popenta May 12, 2025
bf5c689
Merge branch 'main' into merge-main-in-feat-20-05
popenta May 20, 2025
b2e64c4
Merge pull request #614 from multiversx/merge-main-in-feat-20-05
popenta May 20, 2025
edad0e8
governance transactions factory
popenta May 20, 2025
fae4e07
wip: governance controller
popenta May 21, 2025
a2c51b2
fixes after review
popenta May 21, 2025
bd8a5ac
Merge branch 'governance-transactions-factory' into governance-contro…
popenta May 21, 2025
3583974
governance controller and outcome parser
popenta May 22, 2025
5d48c32
fix test description
popenta May 22, 2025
0a32488
Merge pull request #615 from multiversx/governance-transactions-factory
popenta May 22, 2025
457d5e5
Merge branch 'feat/next' into governance-controller
popenta May 22, 2025
9f40f82
fixes after review
popenta May 26, 2025
33ed08b
Merge pull request #616 from multiversx/governance-controller
popenta May 26, 2025
b7867ce
fix BigNumber to BigInt conversion
popenta May 27, 2025
d1ff2df
Merge pull request #617 from multiversx/fix-conversion-from-bignumber…
popenta May 27, 2025
2d75e7b
Merge branch 'feat/next' into MergeMainInMultisig
danielailie Jun 4, 2025
df5c94c
Merge pull request #619 from multiversx/MergeMainInMultisig
danielailie Jun 4, 2025
1aefad0
Bump version
danielailie Jun 4, 2025
43ae624
Merge pull request #620 from multiversx/MultisigReleaseVersion
danielailie Jun 5, 2025
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
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@multiversx/sdk-core",
"version": "14.1.2",
"version": "14.2.0",
"description": "MultiversX SDK for JavaScript and TypeScript",
"author": "MultiversX",
"homepage": "https://multiversx.com",
Expand Down
20 changes: 8 additions & 12 deletions src/abi/smartContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,7 @@ import {
} from "./interface";
import { NativeSerializer } from "./nativeSerializer";
import { Query } from "./query";
import { EndpointDefinition, TypedValue } from "./typesystem";

interface IAbi {
constructorDefinition: EndpointDefinition;

getEndpoints(): EndpointDefinition[];
getEndpoint(name: string | ContractFunction): EndpointDefinition;
}
import { Abi, EndpointDefinition, TypedValue } from "./typesystem";

/**
* * @deprecated component. Use "SmartContractTransactionsFactory" or "SmartContractController", instead.
Expand All @@ -35,7 +28,7 @@ interface IAbi {
*/
export class SmartContract implements ISmartContract {
private address: Address = Address.empty();
private abi?: IAbi;
private abi?: Abi;

/**
* This object contains a function for each endpoint defined by the contract.
Expand All @@ -55,7 +48,7 @@ export class SmartContract implements ISmartContract {
/**
* Create a SmartContract object by providing its address on the Network.
*/
constructor(options: { address?: Address; abi?: IAbi } = {}) {
constructor(options: { address?: Address; abi?: Abi } = {}) {
this.address = options.address || Address.empty();
this.abi = options.abi;

Expand Down Expand Up @@ -105,13 +98,16 @@ export class SmartContract implements ISmartContract {
return this.address;
}

private getAbi(): IAbi {
private getAbi(): Abi {
guardValueIsSet("abi", this.abi);
return this.abi!;
}

getEndpoint(name: string | ContractFunction): EndpointDefinition {
return this.getAbi().getEndpoint(name);
if (typeof name === "string") {
return this.getAbi().getEndpoint(name);
}
return this.getAbi().getEndpoint(name.name);
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/core/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const VM_TYPE_WASM_VM = new Uint8Array([0x05, 0x00]);
export const CONTRACT_DEPLOY_ADDRESS_HEX = "0000000000000000000000000000000000000000000000000000000000000000";
export const DELEGATION_MANAGER_SC_ADDRESS_HEX = "000000000000000000010000000000000000000000000000000000000004ffff";
export const ESDT_CONTRACT_ADDRESS_HEX = "000000000000000000010000000000000000000000000000000000000002ffff";
export const GOVERNANCE_CONTRACT_ADDRESS_HEX = "000000000000000000010000000000000000000000000000000000000003ffff";

export const DEFAULT_MESSAGE_VERSION = 1;
export const MESSAGE_PREFIX = "\x17Elrond Signed Message:\n";
Expand Down
14 changes: 14 additions & 0 deletions src/core/transactionsFactoryConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ export class TransactionsFactoryConfig {
gasLimitNftChangeToDynamic: bigint;
gasLimitUpdateTokenId: bigint;
gasLimitRegisterDynamic: bigint;
gasLimitForProposal: bigint;
gasLimitForVote: bigint;
gasLimitForClosingProposal: bigint;
gasLimitForClearProposals: bigint;
gasLimitForChangeConfig: bigint;
gasLimitForClaimAccumulatedFees: bigint;

constructor(options: { chainID: string }) {
// General-purpose configuration
Expand Down Expand Up @@ -100,5 +106,13 @@ export class TransactionsFactoryConfig {
// Configuration for smart contract operations
this.gasLimitClaimDeveloperRewards = 6000000n;
this.gasLimitChangeOwnerAddress = 6000000n;

// Configuration for governance operations
this.gasLimitForProposal = 50_000_000n;
this.gasLimitForVote = 5_000_000n;
this.gasLimitForClosingProposal = 50_000_000n;
this.gasLimitForClearProposals = 50_000_000n;
this.gasLimitForChangeConfig = 50_000_000n;
this.gasLimitForClaimAccumulatedFees = 1_000_000n;
}
}
13 changes: 13 additions & 0 deletions src/entrypoints/entrypoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
TransactionWatcher,
} from "../core";
import { DelegationController, DelegationTransactionsFactory } from "../delegation";
import { MultisigTransactionsFactory } from "../multisig";
import { MultisigController } from "../multisig/multisigController";
import { ApiNetworkProvider, ProxyNetworkProvider } from "../networkProviders";
import { INetworkProvider } from "../networkProviders/interface";
import { SmartContractTransactionsFactory } from "../smartContracts";
Expand Down Expand Up @@ -180,6 +182,17 @@ export class NetworkEntrypoint {
config: new TransactionsFactoryConfig({ chainID: this.chainId }),
});
}

createMultisigController(abi: Abi): MultisigController {
return new MultisigController({ chainID: this.chainId, networkProvider: this.networkProvider, abi: abi });
}

createMultisigTransactionsFactory(abi: Abi): MultisigTransactionsFactory {
return new MultisigTransactionsFactory({
config: new TransactionsFactoryConfig({ chainID: this.chainId }),
abi: abi,
});
}
}

export class TestnetEntrypoint extends NetworkEntrypoint {
Expand Down
227 changes: 227 additions & 0 deletions src/governance/governanceController.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
import { assert } from "chai";
import { Account } from "../accounts";
import { SmartContractQueryResponse } from "../core";
import { Address } from "../core/address";
import { ProxyNetworkProvider } from "../networkProviders";
import { b64TopicsToBytes, MockNetworkProvider } from "../testutils";
import { KeyPair, UserSecretKey } from "../wallet";
import { GovernanceController } from "./governanceController";
import { Vote } from "./resources";

describe("test governance controller", function () {
const chainID = "D";
const controller = new GovernanceController({
chainID: chainID,
networkProvider: new ProxyNetworkProvider("https://devnet-gateway.multiversx.com"),
});

const commitHash = "1db734c0315f9ec422b88f679ccfe3e0197b9d67";
const governanceAddress = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrlllsrujgla";

const aliceBech32 = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th";
const secretKey = UserSecretKey.fromString("413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9");
const keypair = new KeyPair(secretKey);
const alice = Account.newFromKeypair(keypair);

it("should create transaction for creating new proposal", async function () {
const expectedData = `proposal@${Buffer.from(commitHash).toString("hex")}@0a@0f`;

const transaction = await controller.createTransactionForNewProposal(alice, alice.getNonceThenIncrement(), {
commitHash: commitHash,
startVoteEpoch: 10,
endVoteEpoch: 15,
nativeTokenAmount: 1000_000000000000000000n,
});

assert.equal(transaction.sender.toBech32(), aliceBech32);
assert.equal(transaction.receiver.toBech32(), governanceAddress);
assert.equal(transaction.value, 1000_000000000000000000n);
assert.equal(transaction.chainID, chainID);
assert.equal(transaction.gasLimit, 50_192_500n);
assert.equal(transaction.data.toString(), expectedData);
});

it("should create transaction for voting", async function () {
const transaction = await controller.createTransactionForVoting(alice, alice.getNonceThenIncrement(), {
proposalNonce: 1,
vote: Vote.YES,
});

assert.equal(transaction.sender.toBech32(), aliceBech32);
assert.equal(transaction.receiver.toBech32(), governanceAddress);
assert.equal(transaction.value, 0n);
assert.equal(transaction.chainID, chainID);
assert.equal(transaction.gasLimit, 5_171_000n);
assert.equal(transaction.data.toString(), "vote@01@796573");
});

it("should create transaction for closing proposal", async function () {
const transaction = await controller.createTransactionForClosingProposal(alice, alice.getNonceThenIncrement(), {
proposalNonce: 1,
});

assert.equal(transaction.sender.toBech32(), aliceBech32);
assert.equal(transaction.receiver.toBech32(), governanceAddress);
assert.equal(transaction.value, 0n);
assert.equal(transaction.chainID, chainID);
assert.equal(transaction.gasLimit, 50_074_000n);
assert.equal(transaction.data.toString(), "closeProposal@01");
});

it("should create transaction for clearing ended proposals", async function () {
const expectedData =
"clearEndedProposals@0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8";

const transaction = await controller.createTransactionForClearingEndedProposals(
alice,
alice.getNonceThenIncrement(),
{
proposers: [
alice.address,
Address.newFromBech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"),
],
},
);

assert.equal(transaction.sender.toBech32(), aliceBech32);
assert.equal(transaction.receiver.toBech32(), governanceAddress);
assert.equal(transaction.value, 0n);
assert.equal(transaction.chainID, chainID);
assert.equal(transaction.gasLimit, 150_273_500n);
assert.equal(transaction.data.toString(), expectedData);
});

it("should create transaction for claiming accumulated fees", async function () {
const transaction = await controller.createTransactionForClaimingAccumulatedFees(
alice,
alice.getNonceThenIncrement(),
{},
);

assert.equal(transaction.sender.toBech32(), aliceBech32);
assert.equal(transaction.receiver.toBech32(), governanceAddress);
assert.equal(transaction.value, 0n);
assert.equal(transaction.chainID, chainID);
assert.equal(transaction.gasLimit, 1_080_000n);
assert.equal(transaction.data.toString(), "claimAccumulatedFees");
});

it("should create transaction for changing config", async function () {
const expectedData =
"changeConfig@31303030303030303030303030303030303030303030@3130303030303030303030303030303030303030@35303030@33303030@36303030";

const transaction = await controller.createTransactionForChangingConfig(alice, alice.getNonceThenIncrement(), {
proposalFee: 1000000000000000000000n,
lastProposalFee: 10000000000000000000n,
minQuorum: 5000,
minVetoThreshold: 3000,
minPassThreshold: 6000,
});

assert.equal(transaction.sender.toBech32(), aliceBech32);
assert.equal(transaction.receiver.toBech32(), governanceAddress);
assert.equal(transaction.value, 0n);
assert.equal(transaction.chainID, chainID);
assert.equal(transaction.gasLimit, 50_237_500n);
assert.equal(transaction.data.toString(), expectedData);
});

it("should get voting power", async function () {
const provider = new MockNetworkProvider();
const controller = new GovernanceController({
chainID: chainID,
networkProvider: provider,
});

provider.mockQueryContractOnFunction(
"viewVotingPower",
new SmartContractQueryResponse({
returnDataParts: [Buffer.from("878678326eac900000", "hex")],
returnCode: "ok",
returnMessage: "",
function: "viewVotingPower",
}),
);

const votingPower = await controller.getVotingPower(alice.address);
assert.equal(votingPower, 2500_000000000000000000n);
});

it("should get config", async function () {
const provider = new MockNetworkProvider();
const controller = new GovernanceController({
chainID: chainID,
networkProvider: provider,
});

provider.mockQueryContractOnFunction(
"viewConfig",
new SmartContractQueryResponse({
returnDataParts: [
Buffer.from("1000000000000000000000"),
Buffer.from("0.2000"),
Buffer.from("0.5000"),
Buffer.from("0.3300"),
Buffer.from("1"),
],
returnCode: "ok",
returnMessage: "",
function: "viewConfig",
}),
);

const config = await controller.getConfig();
assert.equal(config.proposalFee, 1000_000000000000000000n);
assert.equal(config.minQuorum, 0.2);
assert.equal(config.minPassThreshold, 0.5);
assert.equal(config.minVetoThreshold, 0.33);
assert.equal(config.lastProposalNonce, 1);
});

it("should get proposal", async function () {
const provider = new MockNetworkProvider();
const controller = new GovernanceController({
chainID: chainID,
networkProvider: provider,
});

provider.mockQueryContractOnFunction(
"viewProposal",
new SmartContractQueryResponse({
returnDataParts: b64TopicsToBytes([
"NjXJrcXeoAAA",
"MWRiNzM0YzAzMTVmOWVjNDIyYjg4ZjY3OWNjZmUzZTAxOTdiOWQ2Nw==",
"AQ==",
"ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=",
"NQ==",
"Nw==",
"",
"",
"",
"",
"",
"ZmFsc2U=",
"ZmFsc2U=",
]),
returnCode: "ok",
returnMessage: "",
function: "viewProposal",
}),
);

const proposal = await controller.getProposal(1);
assert.equal(proposal.cost, 1000_000000000000000000n);
assert.equal(proposal.commitHash, "1db734c0315f9ec422b88f679ccfe3e0197b9d67");
assert.equal(proposal.nonce, 1);
assert.equal(proposal.issuer.toBech32(), aliceBech32);
assert.equal(proposal.startVoteEpoch, 53);
assert.equal(proposal.endVoteEpoch, 55);
assert.equal(proposal.quorumStake, 0n);
assert.equal(proposal.numYesVotes, 0n);
assert.equal(proposal.numNoVotes, 0n);
assert.equal(proposal.numVetoVotes, 0n);
assert.equal(proposal.numAbstainVotes, 0n);
assert.equal(proposal.isClosed, false);
assert.equal(proposal.isPassed, false);
});
});
Loading
Loading