Skip to content

Commit bfecc89

Browse files
author
ci-bot
committed
implement other deployment tools
1 parent 8af0826 commit bfecc89

File tree

7 files changed

+93
-122
lines changed

7 files changed

+93
-122
lines changed

apps/remix-ide/src/app/udapp/run-tab.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ const profile = {
5555
'addInstance',
5656
'resolveContractAndAddInstance',
5757
'showPluginDetails',
58-
'getRunTabAPI'
58+
'getRunTabAPI',
59+
'getAllDeployedInstances',
60+
'setAccount'
5961
]
6062
}
6163

@@ -119,6 +121,14 @@ export class RunTab extends ViewPlugin {
119121
}
120122
}
121123

124+
setAccount(address: string) {
125+
this.emit('setAccountReducer', address)
126+
}
127+
128+
getAllDeployedInstances() {
129+
return this.REACT_API.instances?.instanceList
130+
}
131+
122132
clearAllInstances() {
123133
this.emit('clearAllInstancesReducer')
124134
}

apps/remix-ide/src/blockchain/blockchain.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ export class Blockchain extends Plugin {
607607
}
608608

609609
changeExecutionContext(context, confirmCb, infoCb, cb) {
610-
if (this.currentRequest && this.currentRequest.from && !this.currentRequest.from.startsWith('injected')) {
610+
if (this.currentRequest && this.currentRequest.from && !this.currentRequest.from.startsWith('injected') && this.currentRequest.from !== 'remixAI') {
611611
// only injected provider can update the provider.
612612
return
613613
}

libs/remix-ai-core/src/remix-mcp-server/handlers/DebuggingHandler.ts

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,20 @@ export class StartDebugSessionHandler extends BaseToolHandler {
3030
inputSchema = {
3131
type: 'object',
3232
properties: {
33-
contractAddress: {
34-
type: 'string',
35-
description: 'Contract address to debug',
36-
pattern: '^0x[a-fA-F0-9]{40}$'
37-
},
3833
transactionHash: {
3934
type: 'string',
4035
description: 'Transaction hash to debug (optional)',
4136
pattern: '^0x[a-fA-F0-9]{64}$'
4237
},
43-
sourceFile: {
44-
type: 'string',
45-
description: 'Source file path to debug'
46-
},
38+
/*
4739
network: {
4840
type: 'string',
4941
description: 'Network to debug on',
5042
default: 'local'
5143
}
44+
*/
5245
},
53-
required: ['contractAddress']
46+
required: ['transactionHash']
5447
};
5548

5649
getPermissions(): string[] {
@@ -62,17 +55,10 @@ export class StartDebugSessionHandler extends BaseToolHandler {
6255
if (required !== true) return required;
6356

6457
const types = this.validateTypes(args, {
65-
contractAddress: 'string',
6658
transactionHash: 'string',
67-
sourceFile: 'string',
68-
network: 'string'
6959
});
7060
if (types !== true) return types;
7161

72-
if (!args.contractAddress.match(/^0x[a-fA-F0-9]{40}$/)) {
73-
return 'Invalid contract address format';
74-
}
75-
7662
if (args.transactionHash && !args.transactionHash.match(/^0x[a-fA-F0-9]{64}$/)) {
7763
return 'Invalid transaction hash format';
7864
}
@@ -83,16 +69,11 @@ export class StartDebugSessionHandler extends BaseToolHandler {
8369
async execute(args: DebugSessionArgs, plugin: Plugin): Promise<IMCPToolResult> {
8470
try {
8571
// TODO: Integrate with Remix debugger plugin
86-
const sessionId = 'debug_' + Date.now();
87-
72+
plugin.call('debugger', 'debug', args.transactionHash);
8873
// Mock debug session creation
8974
const result: DebugSessionResult = {
9075
success: true,
91-
sessionId,
92-
contractAddress: args.contractAddress,
93-
network: args.network || 'local',
9476
transactionHash: args.transactionHash,
95-
sourceFile: args.sourceFile,
9677
status: 'started',
9778
createdAt: new Date().toISOString()
9879
};

libs/remix-ai-core/src/remix-mcp-server/handlers/DeploymentHandler.ts

Lines changed: 55 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import {
1414
AccountInfo,
1515
ContractInteractionResult
1616
} from '../types/mcpTools';
17-
import { bytesToHex } from '@ethereumjs/util'
1817
import { Plugin } from '@remixproject/engine';
1918
import { getContractData } from '@remix-project/core-plugin'
2019
import type { TxResult } from '@remix-project/remix-lib';
2120
import type { TransactionReceipt } from 'web3'
22-
import web3 from 'web3'
21+
import { BrowserProvider } from "ethers"
22+
import web3, { Web3 } from 'web3'
2323

2424
/**
2525
* Deploy Contract Tool Handler
@@ -65,7 +65,7 @@ export class DeployContractHandler extends BaseToolHandler {
6565
description: 'The file containing the contract to deploy'
6666
}
6767
},
68-
required: ['contractName']
68+
required: ['contractName', 'file']
6969
};
7070

7171
getPermissions(): string[] {
@@ -116,7 +116,7 @@ export class DeployContractHandler extends BaseToolHandler {
116116
const compilerContracts = await plugin.call('compilerArtefacts', 'getLastCompilationResult')
117117
plugin.call('blockchain', 'deployContractAndLibraries',
118118
data,
119-
args.constructorArgs ? args : [],
119+
args.constructorArgs ? args.constructorArgs : [],
120120
null,
121121
compilerContracts.getData().contracts,
122122
callbacks,
@@ -128,7 +128,6 @@ export class DeployContractHandler extends BaseToolHandler {
128128
}
129129

130130

131-
console.log('txReturn', txReturn)
132131
const receipt = (txReturn.txResult.receipt as TransactionReceipt)
133132
const result: DeploymentResult = {
134133
transactionHash: web3.utils.bytesToHex(receipt.transactionHash),
@@ -216,15 +215,15 @@ export class CallContractHandler extends BaseToolHandler {
216215
description: 'Account to call from'
217216
}
218217
},
219-
required: ['address', 'abi', 'methodName']
218+
required: ['address', 'abi', 'methodName', 'contractName']
220219
};
221220

222221
getPermissions(): string[] {
223222
return ['contract:interact'];
224223
}
225224

226225
validate(args: CallContractArgs): boolean | string {
227-
const required = this.validateRequired(args, ['address', 'abi', 'methodName']);
226+
const required = this.validateRequired(args, ['address', 'abi', 'methodName', 'contractName']);
228227
if (required !== true) return required;
229228

230229
const types = this.validateTypes(args, {
@@ -261,7 +260,7 @@ export class CallContractHandler extends BaseToolHandler {
261260
args.abi,
262261
funcABI,
263262
undefined,
264-
args.args ? args : [],
263+
args.args ? args.args : [],
265264
args.address,
266265
params,
267266
isView,
@@ -314,15 +313,6 @@ export class CallContractHandler extends BaseToolHandler {
314313
return this.createErrorResult(`Contract call failed: ${error.message}`);
315314
}
316315
}
317-
318-
private async getAccounts(plugin: Plugin): Promise<string[]> {
319-
try {
320-
// TODO: Get accounts from Remix API
321-
return ['0x' + Math.random().toString(16).substr(2, 40)]; // Mock account
322-
} catch (error) {
323-
return [];
324-
}
325-
}
326316
}
327317

328318
/**
@@ -397,40 +387,44 @@ export class SendTransactionHandler extends BaseToolHandler {
397387

398388
async execute(args: SendTransactionArgs, plugin: Plugin): Promise<IMCPToolResult> {
399389
try {
400-
// Get accounts
401-
const accounts = await this.getAccounts(plugin);
402-
const sendAccount = args.account || accounts[0];
390+
// Get accounts
391+
const sendAccount = args.account
403392

404393
if (!sendAccount) {
405394
return this.createErrorResult('No account available for sending transaction');
406395
}
396+
const web3: Web3 = await plugin.call('blockchain', 'web3')
397+
const ethersProvider = new BrowserProvider(web3.currentProvider)
398+
const signer = await ethersProvider.getSigner();
399+
const tx = await signer.sendTransaction({
400+
from: args.account,
401+
to: args.to,
402+
value: args.value || '0',
403+
data: args.data,
404+
gasLimit: args.gasLimit,
405+
gasPrice: args.gasPrice
406+
});
407407

408+
// Wait for the transaction to be mined
409+
const receipt = await tx.wait()
408410
// TODO: Send a real transaction via Remix Run Tab API
409411
const mockResult = {
410412
success: true,
411-
transactionHash: '0x' + Math.random().toString(16).substr(2, 64),
412-
from: sendAccount,
413+
transactionHash: receipt.hash,
414+
from: args.account,
413415
to: args.to,
414416
value: args.value || '0',
415-
gasUsed: args.gasLimit || 21000,
416-
blockNumber: Math.floor(Math.random() * 1000000)
417+
gasUsed: web3.utils.toNumber(receipt.gasUsed),
418+
blockNumber: receipt.blockNumber
417419
};
418420

419421
return this.createSuccessResult(mockResult);
420422

421423
} catch (error) {
424+
console.log(error)
422425
return this.createErrorResult(`Transaction failed: ${error.message}`);
423426
}
424427
}
425-
426-
private async getAccounts(plugin: Plugin): Promise<string[]> {
427-
try {
428-
// TODO: Get accounts from Remix API
429-
return ['0x' + Math.random().toString(16).substr(2, 40)]; // Mock account
430-
} catch (error) {
431-
return [];
432-
}
433-
}
434428
}
435429

436430
/**
@@ -455,21 +449,11 @@ export class GetDeployedContractsHandler extends BaseToolHandler {
455449

456450
async execute(args: { network?: string }, plugin: Plugin): Promise<IMCPToolResult> {
457451
try {
458-
// TODO: Get deployed contracts from Remix storage/state
459-
const mockDeployedContracts = [
460-
{
461-
name: 'MyToken',
462-
address: '0x' + Math.random().toString(16).substr(2, 40),
463-
network: args.network || 'local',
464-
deployedAt: new Date().toISOString(),
465-
transactionHash: '0x' + Math.random().toString(16).substr(2, 64)
466-
}
467-
];
468-
452+
const deployedContracts = await plugin.call('udapp', 'getAllDeployedInstances')
469453
return this.createSuccessResult({
470454
success: true,
471-
contracts: mockDeployedContracts,
472-
count: mockDeployedContracts.length
455+
contracts: deployedContracts,
456+
count: deployedContracts.length
473457
});
474458

475459
} catch (error) {
@@ -489,7 +473,7 @@ export class SetExecutionEnvironmentHandler extends BaseToolHandler {
489473
properties: {
490474
environment: {
491475
type: 'string',
492-
enum: ['vm-london', 'vm-berlin', 'injected', 'web3'],
476+
enum: ['vm-prague', 'vm-cancun', 'vm-shanghai', 'vm-paris', 'vm-london', 'vm-berlin', 'vm-mainnet-fork', 'vm-sepolia-fork', 'vm-custom-fork', 'walletconnect', 'basic-http-provider', 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'injected-Rabby Wallet', 'injected-MetaMask', 'injected-metamask-optimism', 'injected-metamask-arbitrum', 'injected-metamask-sepolia', 'injected-metamask-ephemery', 'injected-metamask-gnosis', 'injected-metamask-chiado', 'injected-metamask-linea'],
493477
description: 'Execution environment'
494478
},
495479
networkUrl: {
@@ -505,26 +489,23 @@ export class SetExecutionEnvironmentHandler extends BaseToolHandler {
505489
}
506490

507491
validate(args: { environment: string; networkUrl?: string }): boolean | string {
508-
const required = this.validateRequired(args, ['environment']);
509-
if (required !== true) return required;
510-
511-
const validEnvironments = ['vm-london', 'vm-berlin', 'injected', 'web3'];
512-
if (!validEnvironments.includes(args.environment)) {
513-
return `Invalid environment. Must be one of: ${validEnvironments.join(', ')}`;
514-
}
515-
492+
// we validate in the execute method to have access to the list of available providers.
516493
return true;
517494
}
518495

519-
async execute(args: { environment: string; networkUrl?: string }, plugin: Plugin): Promise<IMCPToolResult> {
496+
async execute(args: { environment: string }, plugin: Plugin): Promise<IMCPToolResult> {
520497
try {
521-
// TODO: Set execution environment via Remix Run Tab API
522-
498+
const providers = await plugin.call('blockchain', 'getAllProviders')
499+
console.log('available providers', Object.keys(providers))
500+
const provider = Object.keys(providers).find((p) => p === args.environment)
501+
if (!provider) {
502+
return this.createErrorResult(`Could not find provider for environment '${args.environment}'`);
503+
}
504+
await plugin.call('blockchain', 'changeExecutionContext', { context: args.environment })
523505
return this.createSuccessResult({
524506
success: true,
525507
message: `Execution environment set to: ${args.environment}`,
526508
environment: args.environment,
527-
networkUrl: args.networkUrl
528509
});
529510

530511
} catch (error) {
@@ -568,16 +549,14 @@ export class GetAccountBalanceHandler extends BaseToolHandler {
568549

569550
async execute(args: { account: string }, plugin: Plugin): Promise<IMCPToolResult> {
570551
try {
571-
// TODO: Get account balance from current provider
572-
const mockBalance = (Math.random() * 10).toFixed(4);
573-
552+
const web3 = await plugin.call('blockchain', 'web3')
553+
const balance = await web3.eth.getBalance(args.account)
574554
return this.createSuccessResult({
575555
success: true,
576556
account: args.account,
577-
balance: mockBalance,
557+
balance: web3.utils.fromWei(balance, 'ether'),
578558
unit: 'ETH'
579-
});
580-
559+
})
581560
} catch (error) {
582561
return this.createErrorResult(`Failed to get account balance: ${error.message}`);
583562
}
@@ -712,9 +691,10 @@ export class SetSelectedAccountHandler extends BaseToolHandler {
712691
try {
713692
// Set the selected account through the udapp plugin
714693
await plugin.call('udapp' as any, 'setAccount', args.address);
694+
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait a moment for the change to propagate
715695

716696
// Verify the account was set
717-
const runTabApi = await plugin.call('udapp' as any, 'getAccounts');
697+
const runTabApi = await plugin.call('udapp' as any, 'getRunTabAPI');
718698
const currentSelected = runTabApi?.accounts?.selectedAccount;
719699

720700
if (currentSelected !== args.address) {
@@ -750,37 +730,25 @@ export class GetCurrentEnvironmentHandler extends BaseToolHandler {
750730
async execute(_args: any, plugin: Plugin): Promise<IMCPToolResult> {
751731
try {
752732
// Get environment information
753-
const provider = await plugin.call('blockchain' as any, 'getCurrentProvider');
754-
const networkName = await plugin.call('blockchain' as any, 'getNetworkName').catch(() => 'unknown');
755-
const chainId = await plugin.call('blockchain' as any, 'getChainId').catch(() => 'unknown');
733+
const provider = await plugin.call('blockchain' as any, 'getProvider');
734+
const network = await plugin.call('network', 'detectNetwork')
756735

757-
// Get accounts info
758-
const runTabApi = await plugin.call('udapp' as any, 'getAccounts');
759-
const accountsCount = runTabApi?.accounts?.loadedAccounts
760-
? Object.keys(runTabApi.accounts.loadedAccounts).length
761-
: 0;
736+
// Verify the account was set
737+
const runTabApi = await plugin.call('udapp' as any, 'getRunTabAPI');
738+
const accounts = runTabApi?.accounts;
762739

763740
const result = {
764741
success: true,
765742
environment: {
766-
provider: {
767-
name: provider?.name || 'unknown',
768-
displayName: provider?.displayName || provider?.name || 'unknown',
769-
kind: provider?.kind || 'unknown'
770-
},
771-
network: {
772-
name: networkName,
773-
chainId: chainId
774-
},
775-
accounts: {
776-
total: accountsCount,
777-
selected: runTabApi?.accounts?.selectedAccount || null
778-
}
743+
provider,
744+
network,
745+
accounts
779746
}
780747
};
781748

782749
return this.createSuccessResult(result);
783750
} catch (error) {
751+
console.error(error)
784752
return this.createErrorResult(`Failed to get environment information: ${error.message}`);
785753
}
786754
}

0 commit comments

Comments
 (0)