Skip to content
This repository was archived by the owner on Apr 22, 2026. It is now read-only.

Commit 3c78651

Browse files
author
Iztok
committed
auto accept owner work address assignment
1 parent 6d36f29 commit 3c78651

13 files changed

Lines changed: 76 additions & 48 deletions

File tree

packages/fasset-bots-cli/src/run/run-agent.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import "source-map-support/register";
33

44
import { AgentBotRunner, PricePublisherService, startActivityTimestampUpdater, stopActivityTimestampUpdater, TimeKeeperService, TimekeeperTimingConfig } from "@flarenetwork/fasset-bots-core";
55
import { closeBotConfig, createBotConfig, loadAgentConfigFile, Secrets } from "@flarenetwork/fasset-bots-core/config";
6-
import { assertNotNullCmd, authenticatedHttpProvider, CommandLineError, formatFixed, initWeb3, isNotNull, logger, sendWeb3Transaction, toBN, toBNExp, web3 } from "@flarenetwork/fasset-bots-core/utils";
6+
import { assertCmd, assertNotNullCmd, authenticatedHttpProvider, CommandLineError, formatFixed, initWeb3, isNotNull, logger, sendWeb3Transaction, toBN, toBNExp, web3 } from "@flarenetwork/fasset-bots-core/utils";
77
import BN from "bn.js";
88
import { programWithCommonOptions } from "../utils/program";
99
import { toplevelRun } from "../utils/toplevel";
@@ -78,7 +78,7 @@ program.action(async () => {
7878
// create timekeepers
7979
const timekeeperService = await TimeKeeperService.create(botConfig, timekeeper.address, timekeeperConfig);
8080
timekeeperService.startAll();
81-
// run price publisher only if price feed api path is set
81+
// run price publisher (only if price feed api path is set)
8282
let pricePublisherService: PricePublisherService | null = null;
8383
if (runConfig.pricePublisherConfig?.enabled) {
8484
assertNotNullCmd(pricePublisher, "Price publisher address and private key required");
@@ -89,6 +89,9 @@ program.action(async () => {
8989
pricePublisherService = await PricePublisherService.create(runConfig, secrets, pricePublisher.address);
9090
pricePublisherService.start();
9191
}
92+
// update work address mapping
93+
const workAddressCorrect = await AgentBotRunner.acceptOwnerWorkAddressAssignment(botConfig);
94+
assertCmd(workAddressCorrect, `Work address ${owner.address} does not match owner's management address. Please use setWorkAddress.`);
9295
// create runner and agents
9396
const runner = await AgentBotRunner.create(secrets, botConfig, timekeeperService);
9497
runner.serviceAccounts = serviceAccounts;

packages/fasset-bots-core/src/actors/AgentBot.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ export class AgentBot {
224224
return new AgentBot(agent, agentBotSettings, notifier, owner, ownerUnderlyingAddress);
225225
}
226226

227+
static ownerAddressPair(secrets: Secrets) {
228+
return new OwnerAddressPair(secrets.required("owner.management.address"), secrets.required("owner.native.address"));
229+
}
230+
227231
static underlyingAddress(secrets: Secrets, chainId: ChainId) {
228232
return secrets.required(`owner.${chainId.chainName}.address`);
229233
}

packages/fasset-bots-core/src/actors/AgentBotRunner.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ORM } from "../config/orm";
88
import { AgentEntity } from "../entities/agent";
99
import { IAssetAgentContext } from "../fasset-bots/IAssetBotContext";
1010
import { ChainId } from "../underlying-chain/ChainId";
11-
import { EVMNativeTokenBalance, sendWeb3Transaction, SimpleThrottler, squashSpace } from "../utils";
11+
import { artifacts, EVMNativeTokenBalance, sendWeb3Transaction, SimpleThrottler, squashSpace } from "../utils";
1212
import { firstValue, getOrCreate, requireNotNull, sleep } from "../utils/helpers";
1313
import { logger } from "../utils/logger";
1414
import { AgentNotifier } from "../utils/notifier/AgentNotifier";
@@ -262,6 +262,13 @@ export class AgentBotRunner {
262262
return new AgentBotRunner(secrets, contexts, settings, botConfig.orm, botConfig.loopDelay, botConfig.notifiers, timekeeperService);
263263
}
264264

265+
static async acceptOwnerWorkAddressAssignment(botConfig: AgentBotConfig) {
266+
const AgentOwnerRegistry = artifacts.require("AgentOwnerRegistry");
267+
const owner = AgentBot.ownerAddressPair(botConfig.secrets);
268+
const agentOwnerRegistry = await botConfig.contractRetriever.getContract(AgentOwnerRegistry);
269+
return await owner.acceptWorkAddressAssignment(agentOwnerRegistry);
270+
}
271+
265272
async addSimpleWalletToLoop(agentBot: AgentBot) {
266273
this.agentAddressFromUnderlying.set(agentBot.agent.underlyingAddress, agentBot.agent.vaultAddress);
267274
const chainId = agentBot.context.chainInfo.chainId;

packages/fasset-bots-core/src/commands/AgentBotCommands.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class AgentBotCommands {
7171
}
7272

7373
static async createBotConfig(secrets: Secrets, configFileName: string, registerCleanup?: CleanupRegistration, validate: boolean = true) {
74-
const owner = AgentBotCommands.getOwnerAddressPair(secrets);
74+
const owner = AgentBot.ownerAddressPair(secrets);
7575
// load config
7676
logger.info(`Owner ${owner.managementAddress} started to initialize cli environment.`);
7777
const configFile = loadAgentConfigFile(configFileName, `Owner ${owner.managementAddress}`);
@@ -96,7 +96,8 @@ export class AgentBotCommands {
9696
assertNotNullCmd(chainConfig, `Invalid FAsset symbol ${fAssetSymbol}`);
9797
const context = await createAgentBotContext(botConfig, chainConfig);
9898
// verify keys
99-
const owner = AgentBotCommands.getOwnerAddressPair(secrets);
99+
const owner = AgentBot.ownerAddressPair(secrets);
100+
await owner.acceptWorkAddressAssignment(context.agentOwnerRegistry);
100101
if (validate) {
101102
await AgentBotOwnerValidation.verifyAgentWhitelisted(context.agentOwnerRegistry, owner);
102103
await AgentBotOwnerValidation.verifyWorkAddress(context.agentOwnerRegistry, owner);
@@ -110,10 +111,6 @@ export class AgentBotCommands {
110111
return new AgentBotCommands(context, chainConfig.agentBotSettings, owner, underlyingAddress, botConfig.orm, botConfig.notifiers);
111112
}
112113

113-
static getOwnerAddressPair(secrets: Secrets) {
114-
return new OwnerAddressPair(secrets.required("owner.management.address"), secrets.required("owner.native.address"));
115-
}
116-
117114
notifierFor(agentVault: string) {
118115
return new AgentNotifier(agentVault, this.notifiers);
119116
}

packages/fasset-bots-core/src/commands/AgentBotOwnerValidation.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ZERO_ADDRESS, requireNotNull } from "../utils/helpers";
1616
import { logger } from "../utils/logger";
1717
import { artifacts, authenticatedHttpProvider, initWeb3, web3 } from "../utils/web3";
1818
import { ORM } from "../config/orm";
19+
import { AgentBot } from "../actors/AgentBot";
1920

2021
const AgentOwnerRegistry = artifacts.require("AgentOwnerRegistry");
2122

@@ -53,7 +54,7 @@ export class AgentBotOwnerValidation {
5354

5455
static async create(secretsFile: string, configFileName: string, reporter: Reporter = throwingReporter) {
5556
const secrets = await Secrets.load(secretsFile);
56-
const owner = new OwnerAddressPair(secrets.required("owner.management.address"), secrets.required("owner.native.address"));
57+
const owner = AgentBot.ownerAddressPair(secrets);
5758
const configFile = loadConfigFile(configFileName);
5859
const apiKey = secrets.optional("apiKey.native_rpc");
5960
await initWeb3(authenticatedHttpProvider(configFile.rpcUrl, apiKey), [], null);
@@ -68,7 +69,7 @@ export class AgentBotOwnerValidation {
6869

6970
static async fromContext(context: IAssetAgentContext, secretsFile: string, configFileName: string, reporter: Reporter = throwingReporter) {
7071
const secrets = await Secrets.load(secretsFile);
71-
const owner = new OwnerAddressPair(secrets.required("owner.management.address"), secrets.required("owner.native.address"));
72+
const owner = AgentBot.ownerAddressPair(secrets);
7273
const configFile = loadConfigFile(configFileName);
7374
const fassets = new Map<string, FAssetInstance>([[context.fAssetSymbol, context.fAsset]]);
7475
const botConfig = await createBotConfig("agent", secrets, configFile, owner.workAddress);
@@ -97,6 +98,7 @@ export class AgentBotOwnerValidation {
9798
this.reporter.log(`Verifying owner whitelisting...`);
9899
await AgentBotOwnerValidation.verifyAgentWhitelisted(this.agentOwnerRegistry, owner, this.reporter);
99100
this.reporter.log(`Verifying owner work address...`);
101+
await owner.acceptWorkAddressAssignment(this.agentOwnerRegistry);
100102
await AgentBotOwnerValidation.verifyWorkAddress(this.agentOwnerRegistry, owner, this.reporter);
101103
await this.verifyOwnerManagementBalance(owner);
102104
await this.verifyOwnerWorkBalance(owner);

packages/fasset-bots-core/src/fasset/Agent.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { AddressValidity } from "@flarenetwork/state-connector-protocol";
22
import BN from "bn.js";
3-
import { AgentVaultInstance, CollateralPoolInstance, CollateralPoolTokenInstance } from "../../typechain-truffle";
3+
import { AgentOwnerRegistryInstance, AgentVaultInstance, CollateralPoolInstance, CollateralPoolTokenInstance } from "../../typechain-truffle";
44
import {
55
AgentAvailable,
66
AgentDestroyed,
@@ -35,13 +35,22 @@ const IERC20 = artifacts.require("IERC20");
3535

3636
export class OwnerAddressPair {
3737
constructor(
38-
public managementAddress: string,
39-
public workAddress: string,
38+
public readonly managementAddress: string,
39+
public readonly workAddress: string,
4040
) {}
4141

4242
toString() {
4343
return `${this.managementAddress} with work address ${this.workAddress}`;
4444
}
45+
46+
async acceptWorkAddressAssignment(agentOwnerRegistry: AgentOwnerRegistryInstance) {
47+
const currentWorkAddress = await agentOwnerRegistry.getWorkAddress(this.managementAddress);
48+
if (currentWorkAddress === this.workAddress) return true;
49+
const pendingWorkAddress = await agentOwnerRegistry.getPendingWorkAddress(this.managementAddress);
50+
if (pendingWorkAddress !== this.workAddress) return false;
51+
await agentOwnerRegistry.acceptWorkAddressAssignment(this.managementAddress, { from: this.workAddress });
52+
return true;
53+
}
4554
}
4655

4756
export class Agent {
@@ -77,13 +86,11 @@ export class Agent {
7786
return getAgentSettings(agentInfo);
7887
}
7988

80-
8189
async getAgentSetting(settingsName: string): Promise<BN | string> {
8290
const settings = await this.assetManager.getAgentSetting(this.vaultAddress, settingsName)
8391
return settings;
8492
}
8593

86-
8794
async getAgentInfo(): Promise<AgentInfo> {
8895
return await this.assetManager.getAgentInfo(this.agentVault.address);
8996
}

packages/fasset-bots-core/test-hardhat/integration/agentBot.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { FaultyNotifierTransport } from "../test-utils/FaultyNotifierTransport";
2727
import { TestAssetBotContext, createTestAssetContext } from "../test-utils/create-test-asset-context";
2828
import { loadFixtureCopyVars } from "../test-utils/hardhat-test-helpers";
2929
import { QUERY_WINDOW_SECONDS, convertFromUSD5, createCRAndPerformMinting, createCRAndPerformMintingAndRunSteps, createTestAgent, createTestAgentAndMakeAvailable, createTestAgentBotAndMakeAvailable, createTestMinter, createTestRedeemer, getAgentStatus, mintVaultCollateralToOwner, runWithManualFDCFinalization, updateAgentBotUnderlyingBlockProof } from "../test-utils/helpers";
30+
import { OwnerAddressPair } from "../../src/fasset/Agent";
3031
use(spies);
3132

3233
const IERC20 = artifacts.require("IERC20");
@@ -50,12 +51,16 @@ describe("Agent bot tests", () => {
5051

5152
async function testWhitelistAndSetWorkAddress(agentOwnerRegistry: AgentOwnerRegistryInstance, managementAddress: string, managementPrivateKey: string, workAddress: string) {
5253
await agentOwnerRegistry.whitelistAndDescribeAgent(managementAddress, "Agent Name", "Agent Description", "Icon", "URL");
54+
// set work address, signing it "externally" with management private key
5355
const methodAbi = requireNotNull(agentOwnerRegistry.abi.find(it => it.name === "setWorkAddress"));
5456
const data = web3.eth.abi.encodeFunctionCall(methodAbi, [workAddress]);
5557
const account = web3.eth.accounts.privateKeyToAccount(managementPrivateKey);
5658
assert.equal(account.address, managementAddress);
5759
const signedTx = await web3.eth.accounts.signTransaction({ from: managementAddress, to: agentOwnerRegistry.address, data: data, gas: 100000 }, managementPrivateKey);
5860
await web3.eth.sendSignedTransaction(requireNotNull(signedTx.rawTransaction));
61+
// accept work address
62+
const owner = new OwnerAddressPair(managementAddress, workAddress);
63+
await owner.acceptWorkAddressAssignment(agentOwnerRegistry);
5964
}
6065

6166
before(async () => {

packages/fasset-bots-core/test-hardhat/integration/runner-and-commands.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ describe("Toplevel runner and commands integration test", () => {
2929
const loopDelay = 100; // ms
3030
let accounts: string[];
3131
let orm: ORM;
32-
let ownerManagementAddress: string;
32+
let owner: OwnerAddressPair;
3333
const ownerUnderlyingAddress = "owner_underlying_1";
34-
let ownerWorkAddress: string;
3534
let userAddress: string;
3635
let submitterAddress: string;
3736
const userUnderlyingAddress = "user_underlying_1";
@@ -118,8 +117,7 @@ describe("Toplevel runner and commands integration test", () => {
118117
}
119118

120119
function createAgentCommands(context: IAssetAgentContext) {
121-
const ownerAddressPair = new OwnerAddressPair(ownerManagementAddress, ownerWorkAddress);
122-
return new AgentBotCommands(context, agentBotSettings, ownerAddressPair, ownerUnderlyingAddress, orm, testNotifierTransports);
120+
return new AgentBotCommands(context, agentBotSettings, owner, ownerUnderlyingAddress, orm, testNotifierTransports);
123121
}
124122

125123
async function createUserCommands(context: IAssetAgentContext) {
@@ -128,8 +126,7 @@ describe("Toplevel runner and commands integration test", () => {
128126

129127
before(async () => {
130128
accounts = await web3.eth.getAccounts();
131-
ownerManagementAddress = accounts[2];
132-
ownerWorkAddress = accounts[3];
129+
owner = new OwnerAddressPair(accounts[2], accounts[3]);
133130
userAddress = accounts[4];
134131
submitterAddress = accounts[5];
135132
});
@@ -142,7 +139,7 @@ describe("Toplevel runner and commands integration test", () => {
142139
const fdcHub = await FdcHub.at(contracts.FdcHub.address);
143140
const flareDataConnectorClient = new MockFlareDataConnectorClient(fdcHub, relay, {}, "auto", submitterAddress);
144141
// secrets
145-
secrets = createTestSecrets(testChainInfos.map(ci => ci.chainId), ownerManagementAddress, ownerWorkAddress, ownerUnderlyingAddress);
142+
secrets = createTestSecrets(testChainInfos.map(ci => ci.chainId), owner.managementAddress, owner.workAddress, ownerUnderlyingAddress);
146143
// create contexts
147144
for (const chainInfo of testChainInfos) {
148145
const chain = await getOrCreateAsync(chains, chainInfo.chainId, () => createTestChain(chainInfo));
@@ -152,22 +149,23 @@ describe("Toplevel runner and commands integration test", () => {
152149
}
153150
// set work address mapping
154151
const context0 = firstValue(contexts)!;
155-
await context0.agentOwnerRegistry.whitelistAndDescribeAgent(ownerManagementAddress, "Agent Name", "Agent Description", "Icon", "URL");
156-
await context0.agentOwnerRegistry.setWorkAddress(ownerWorkAddress, { from: ownerManagementAddress });
152+
await context0.agentOwnerRegistry.whitelistAndDescribeAgent(owner.managementAddress, "Agent Name", "Agent Description", "Icon", "URL");
153+
await context0.agentOwnerRegistry.setWorkAddress(owner.workAddress, { from: owner.managementAddress });
154+
await owner.acceptWorkAddressAssignment(context0.agentOwnerRegistry);
157155
// decrease setting change time
158156
const assetManagers = await context0.assetManagerController.getAssetManagers();
159157
const resSetUpd = await context0.assetManagerController.setAgentFeeChangeTimelockSeconds(assetManagers, 300);
160158
await waitForTimelock(resSetUpd, context0.assetManagerController, await context0.assetManagerController.governance());
161159
// timekeeper
162-
timekeeperService = new TimeKeeperService(contexts, ownerWorkAddress, testTimekeeperTimingConfig({ loopDelayMs: loopDelay }));
160+
timekeeperService = new TimeKeeperService(contexts, owner.workAddress, testTimekeeperTimingConfig({ loopDelayMs: loopDelay }));
163161
// agent bot runner
164162
botRunner = new AgentBotRunner(secrets, contexts, agentBotSettingsMap, orm, loopDelay, testNotifierTransports, timekeeperService);
165163
// currencies
166164
const usdc = context0.stablecoins.usdc as FakeERC20Instance;
167165
usdcCurrency = await Currencies.erc20(usdc as IERC20MetadataInstance);
168166
xrpCurrency = Currencies.chain(testXrpChainInfo);
169167
// mint some collaterals to owner
170-
await usdc.mintAmount(ownerWorkAddress, usdcCurrency.parse("1000"));
168+
await usdc.mintAmount(owner.workAddress, usdcCurrency.parse("1000"));
171169
// mint some underlying
172170
for (const chain of chains.values()) {
173171
// to owner

0 commit comments

Comments
 (0)