Skip to content
4 changes: 3 additions & 1 deletion contracts/hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ module.exports = {
accounts: ["0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e"], // Replace with your private key
},
seilocal: {
url: "http://127.0.0.1:8545",
// SEI_EVM_RPC lets a non-docker runner point at the node's dynamic EVM
// endpoint; unset → the docker localnode's in-container :8545.
url: process.env.SEI_EVM_RPC || "http://127.0.0.1:8545",
address: ["0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8","0x817E1414b633948e50101Df0b722DeA5f8C29109"],
accounts: ["0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e", "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d","0x888432482e2cbcf4e2b248a388f2a6d9fe7b59a11e9136fd615942d7421e89bf"],
},
Expand Down
10 changes: 6 additions & 4 deletions contracts/test/EVMCompatabilityTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,7 @@ describe("EVM Validations ", function() {
gasLimit: 21000,
maxFeePerGas: 400000000000})

const nodeUrl = 'http://localhost:8545';
const nodeUrl = process.env.SEI_EVM_RPC || 'http://localhost:8545';
const response = await axios.post(nodeUrl, {
method: 'eth_sendRawTransaction',
params: [signedTx],
Expand All @@ -1351,7 +1351,7 @@ describe("EVM Validations ", function() {
gasPrice: 1000000000000,
gasLimit: 21000})

const nodeUrl = 'http://localhost:8545';
const nodeUrl = process.env.SEI_EVM_RPC || 'http://localhost:8545';
const response = await axios.post(nodeUrl, {
method: 'eth_sendRawTransaction',
params: [signedTx],
Expand All @@ -1374,7 +1374,7 @@ describe("EVM Validations ", function() {
gasPrice: 1000000000000,
gasLimit: 21000})

const nodeUrl = 'http://localhost:8545';
const nodeUrl = process.env.SEI_EVM_RPC || 'http://localhost:8545';
const response = await axios.post(nodeUrl, {
method: 'eth_sendRawTransaction',
params: [signedTx],
Expand Down Expand Up @@ -1568,7 +1568,9 @@ describe("SSTORE Gas Discrepancy Test", function() {
}
});

it("should reproduce mismatch by changing param between execution and trace", async function() {
// Skipped in-process: drives an EVM-param gov proposal that assumes the docker
// localnode's gov topology (same coupling as the skipped YAML gov suite).
(process.env.SEI_IN_PROCESS ? it.skip : it)("should reproduce mismatch by changing param between execution and trace", async function() {
this.timeout(120000); // 2 minutes for governance proposals

const { proposeParamChange, passProposal } = require("./lib.js");
Expand Down
7 changes: 6 additions & 1 deletion contracts/test/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ const crypto = require("crypto");

const adminKeyName = "admin"

// SEI_EVM_RPC (set by the in-process runner) points `seid tx evm` eth-submitting
// commands at the node's dynamic EVM endpoint. Unset under docker → empty, so the
// CLI's in-container :8545 default stands and the docker commands are byte-identical.
const evmRpcFlag = process.env.SEI_EVM_RPC ? ` --evm-rpc ${process.env.SEI_EVM_RPC}` : ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EVM RPC flag partially wired

Medium Severity

The in-process runner sets SEI_EVM_RPC to the node’s dynamic EVM endpoint, and this change adds evmRpcFlag for that purpose, but only evmSend uses it. associateKey, associateKeyStrict, and associateWasm still invoke seid tx evm without --evm-rpc, so those calls keep the CLI’s default :8545 while Hardhat uses the repointed RPC.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 718000e. Configure here.


const ABI = {
ERC20: [
"function name() view returns (string)",
Comment on lines 5 to 15

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The new TestInProcessEVMModuleCompat (integration_test/runner/runner_evm_inprocess_test.go) sets SEI_IN_PROCESS=1 and prepends a seid shim on PATH via InProcessEVMEnv, but contracts/test/lib.js's isDocker() (lines 1020-1030) still returns true whenever a sei-node-0 container is running on the host — regardless of the in-process signal. If a developer has a docker cluster left over from make docker-cluster-start, every seid call routes through docker exec sei-node-0 (bypassing the PATH shim), while hardhat's JSON-RPC still targets the in-process node via SEI_EVM_RPC — split-brain, and the suite hangs waiting for a funding tx that landed on the wrong chain. Trivial one-line fix: if (process.env.SEI_IN_PROCESS) return false at the top of isDocker().

Extended reasoning...

What the bug is

The PR introduces TestInProcessEVMModuleCompat — the first inprocess test that drives hardhat + lib.js — and its comment at integration_test/runner/runner_evm_inprocess_test.go:16-17 asserts that lib.js's isDocker() "falls through to the shimmed seid on PATH". That fall-through only happens when no sei-node-0 container is running. On a dev host with a lingering docker cluster, isDocker() returns true and every subsequent seid call is rerouted through docker — even though the caller wired everything for the in-process node.

Code path

  1. InProcessEVMEnv (integration_test/runner/runner_inprocess.go:39-61) exports SEI_EVM_RPC/EVM_RPC_URL pointing at the in-process node's dynamic EVM endpoint, SEID_HOME/SEID_NODE for the shim, prepends the shim on PATH, and sets SEI_IN_PROCESS=1.
  2. Hardhat's seilocal provider (contracts/hardhat.config.js:30) picks up SEI_EVM_RPC and dials the in-process node — good.
  3. setupSignersfundAddressevmSend at contracts/test/lib.js:150 calls execute("seid tx evm send ... -b sync -y --evm-rpc <in-process RPC>").
  4. execute() (contracts/test/lib.js:1046-1053) calls isDocker(), which at contracts/test/lib.js:1020-1030 only checks docker ps --filter name=sei-node-0 — it never reads SEI_IN_PROCESS. With a stale container present, it returns true.
  5. execute() then wraps the command in docker exec sei-node-0 /bin/bash -c 'export PATH=$PATH:/root/go/bin:/root/.foundry/bin && ... | seid tx evm send ...'. The docker exec uses the container's PATH (hardcoded above), so the harness's host-side seid shim is bypassed; the container's own seid binary runs against the docker chain's keyring/RPC.
  6. waitForReceipt (via ethers/SEI_EVM_RPC) polls the in-process chain for that tx hash — which lives on the docker chain, or (if --evm-rpc <in-process-loopback-port> reaches the container's loopback with nothing listening) never lands at all.

Why existing safeguards do not catch it

SEI_IN_PROCESS is set by InProcessEVMEnv at line 56 and consumed only at contracts/test/EVMCompatabilityTest.js:1573 to gate the gov spec. A grep across contracts/ confirms lib.js has zero references to it. The seid shim on host PATH is bypassed because docker exec resets the environment inside the container.

Step-by-step proof

  1. Developer runs make docker-cluster-start for docker YAML work; container sei-node-0 is up.
  2. Later they run go test -tags inprocess -run TestInProcessEVMModuleCompat ./integration_test/runner/.
  3. InProcessEVMEnv sets PATH=<shim-dir>:..., SEI_EVM_RPC=http://127.0.0.1:<inprocess-port>, SEI_IN_PROCESS=1.
  4. Hardhat loads EVMCompatabilityTest.js; before runs setupSignersfundAddress(evmAddr)evmSend(...).
  5. evmSend calls execute('seid tx evm send ... --evm-rpc http://127.0.0.1:<inprocess-port>').
  6. isDocker() shells docker ps --filter name=sei-node-0; the leftover container is listed → returns true.
  7. execute() wraps the command in docker exec sei-node-0 .... The container's own seid binary runs, using its own keyring/config; it either signs against the docker admin key (wrong chain) or fails to reach 127.0.0.1:<inprocess-port> (container loopback).
  8. The printed tx hash (if any) refers to the docker chain. waitForReceipt(hash) polls the in-process node via SEI_EVM_RPC — the tx never appears there.
  9. waitForReceipt loops forever until the outer 60s execCommand cap or hardhat's mocha timeout kicks in; the developer sees a confusing hang at setupSigners.

Impact

Local-dev-only footgun. CI never has both a docker cluster and the inprocess job in the same runner, so this doesn't affect the PR's green build. The failure is loud (hang / clear connection error), not silent data corruption, and the workaround (docker rm -f sei-node-0) is obvious once diagnosed. But the test's own comment ("isDocker() falls through to the shimmed seid on PATH") is misleading — it only holds under an unstated invariant.

How to fix

Add a one-liner at the top of isDocker() in contracts/test/lib.js:

async function isDocker() {
    if (process.env.SEI_IN_PROCESS) return false;
    return new Promise((resolve, reject) => {
        exec("docker ps --filter 'name=sei-node-0' --format '{{.Names}}'", ...);
    });
}

This makes the in-process signal InProcessEVMEnv already sets authoritative for the docker-detection path, matching how EVMCompatabilityTest.js already consumes it. Optionally update the misleading comment at runner_evm_inprocess_test.go:16-17 to note the gating.

Expand Down Expand Up @@ -142,7 +147,7 @@ async function evmSend(addr, fromKey, amount="10000000000000000000000000") {
// seid tx evm send prints "Transaction hash: 0x..." on its own format
// (not the standard cosmos JSON response), so we extract from text and
// wait via the JSON-RPC receipt — semantically equivalent to -b block.
const output = await execute(`seid tx evm send ${addr} ${amount} --from ${fromKey} -b sync -y`);
const output = await execute(`seid tx evm send ${addr} ${amount} --from ${fromKey} -b sync -y${evmRpcFlag}`);
const evmTxHash = output.replace(/.*0x/, "0x").trim()
await waitForReceipt(evmTxHash)
return evmTxHash
Expand Down
97 changes: 97 additions & 0 deletions inprocess/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"os"
"path/filepath"
"time"

"github.com/sei-protocol/sei-chain/sei-cosmos/client"
"github.com/sei-protocol/sei-chain/sei-cosmos/client/tx"
Expand All @@ -19,9 +20,12 @@ import (
banktypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/bank/types"
"github.com/sei-protocol/sei-chain/sei-cosmos/x/genutil"
genutiltypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/genutil/types"
govtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/gov/types"
stakingtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/staking/types"
tmtime "github.com/sei-protocol/sei-chain/sei-tendermint/libs/time"
tmtypes "github.com/sei-protocol/sei-chain/sei-tendermint/types"
epochtypes "github.com/sei-protocol/sei-chain/x/epoch/types"
minttypes "github.com/sei-protocol/sei-chain/x/mint/types"
)

// genesisBuilder accumulates per-validator accounts, balances, and gentxs across
Expand All @@ -43,6 +47,12 @@ type genesisBuilder struct {

accounts []authtypes.GenesisAccount
balances []banktypes.Balance

// Genesis-parity knobs (from Options); zero values skip the mutation.
useiSupplyTarget *sdk.Int
mintSchedule []MintRelease
govParams *GovParams
mintRef time.Time // one instant driving both the mint schedule + epoch clock
}

// operatorKeyName is the keyring name each node's validator operator key is stored
Expand Down Expand Up @@ -138,6 +148,12 @@ func (b *genesisBuilder) fundAccount(
// writeBaseGenesis writes a base genesis file (accounts + balances, empty
// validator set) to every validator's genesis path. Mirrors initGenFiles.
func (b *genesisBuilder) writeBaseGenesis(baseState map[string]json.RawMessage, genFiles []string) error {
// Credit the reserve (if any) before the auth+bank fold so both the account and
// its balance land in the marshaled state below.
if err := b.creditReserve(); err != nil {
return err
}

var authGenState authtypes.GenesisState
b.codec.MustUnmarshalJSON(baseState[authtypes.ModuleName], &authGenState)
packed, err := authtypes.PackAccounts(b.accounts)
Expand All @@ -152,6 +168,9 @@ func (b *genesisBuilder) writeBaseGenesis(baseState map[string]json.RawMessage,
bankGenState.Balances = append(bankGenState.Balances, b.balances...)
baseState[banktypes.ModuleName] = b.codec.MustMarshalJSON(&bankGenState)

b.applyMintSchedule(baseState)
b.applyGovParams(baseState)

appStateJSON, err := json.MarshalIndent(baseState, "", " ")
if err != nil {
return err
Expand All @@ -169,6 +188,84 @@ func (b *genesisBuilder) writeBaseGenesis(baseState map[string]json.RawMessage,
return nil
}

// creditReserve appends a fixed keyless reserve account + balance so total genesis
// usei == useiSupplyTarget. Bank InitGenesis derives supply from balances (writeBaseGenesis
// leaves bank.Supply empty), so the supply invariant holds. No-op when the target is nil.
func (b *genesisBuilder) creditReserve() error {
if b.useiSupplyTarget == nil {
return nil
}
existing := sdk.ZeroInt()
for _, bal := range b.balances {
existing = existing.Add(bal.Coins.AmountOf(b.bondDenom))
}
shortfall := b.useiSupplyTarget.Sub(existing)
if shortfall.IsNegative() {
return fmt.Errorf("inprocess: GenesisUseiSupply %s is below already-funded %s %s", b.useiSupplyTarget, b.bondDenom, existing)
}
// A stable, collision-free address deriver; never signed from, so no keyring entry
// and a plain BaseAccount (not a registered ModuleAccount).
addr := authtypes.NewModuleAddress("inprocess_genesis_reserve")
b.accounts = append(b.accounts, authtypes.NewBaseAccount(addr, nil, 0, 0))
if shortfall.IsPositive() {
b.balances = append(b.balances, banktypes.Balance{
Address: addr.String(),
Coins: sdk.NewCoins(sdk.NewCoin(b.bondDenom, shortfall)),
})
}
return nil
}

// applyMintSchedule rewrites the mint genesis with the schedule (dates resolved from
// mintRef) + mint_denom, and pins the epoch clock to mintRef so the first epoch's
// CurrentEpochStartTime shares the schedule's start UTC date — the two must be derived
// from one instant, or the mint suite's START_DATE==LAST_MINT_DATE assertion races
// across midnight. No-op when the schedule is empty.
func (b *genesisBuilder) applyMintSchedule(baseState map[string]json.RawMessage) {
if len(b.mintSchedule) == 0 {
return
}
day := b.mintRef.Truncate(24 * time.Hour)
sched := make([]minttypes.ScheduledTokenRelease, 0, len(b.mintSchedule))
for _, r := range b.mintSchedule {
sched = append(sched, minttypes.ScheduledTokenRelease{
StartDate: day.AddDate(0, 0, r.StartDaysFromGenesis).Format(minttypes.TokenReleaseDateFormat),
EndDate: day.AddDate(0, 0, r.EndDaysFromGenesis).Format(minttypes.TokenReleaseDateFormat),
TokenReleaseAmount: r.Amount.Uint64(),
})
}
var mintGen minttypes.GenesisState
b.codec.MustUnmarshalJSON(baseState[minttypes.ModuleName], &mintGen)
mintGen.Params.MintDenom = b.bondDenom
mintGen.Params.TokenReleaseSchedule = sched
baseState[minttypes.ModuleName] = b.codec.MustMarshalJSON(&mintGen)

var epochGen epochtypes.GenesisState
b.codec.MustUnmarshalJSON(baseState[epochtypes.ModuleName], &epochGen)
epochGen.Epoch.GenesisTime = b.mintRef
epochGen.Epoch.CurrentEpochStartTime = b.mintRef
baseState[epochtypes.ModuleName] = b.codec.MustMarshalJSON(&epochGen)
}

// applyGovParams overrides the gov voting/deposit/tally params. No-op when nil; the
// default 2-day voting period never resolves the gov suites' short-sleep votes.
func (b *genesisBuilder) applyGovParams(baseState map[string]json.RawMessage) {
if b.govParams == nil {
return
}
p := b.govParams
var govGen govtypes.GenesisState
b.codec.MustUnmarshalJSON(baseState[govtypes.ModuleName], &govGen)
govGen.VotingParams.VotingPeriod = p.VotingPeriod
govGen.VotingParams.ExpeditedVotingPeriod = p.ExpeditedVotingPeriod
govGen.DepositParams.MaxDepositPeriod = p.MaxDepositPeriod
govGen.TallyParams.Quorum = p.Quorum
govGen.TallyParams.Threshold = p.Threshold
govGen.TallyParams.ExpeditedQuorum = p.ExpeditedQuorum
govGen.TallyParams.ExpeditedThreshold = p.ExpeditedThreshold
baseState[govtypes.ModuleName] = b.codec.MustMarshalJSON(&govGen)
}

// collectGentxs folds every validator's gentx into each node's genesis app state
// under one canonical genesis time (consensus timestamp validation diverges if
// the nodes disagree on GenesisTime). Mirrors collectGenFiles.
Expand Down
79 changes: 75 additions & 4 deletions inprocess/harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,59 @@ type Options struct {
// validator operator the harness provisions (see operatorKeyName), and
// provisionExtraKeys rejects it.
ExtraKeys []ExtraKey

// GenesisUseiSupply, when non-nil, pins total genesis usei supply to this exact
// amount: after validators + ExtraKeys are funded, a fixed keyless reserve account
// is credited (target - sum of existing usei), decoupling supply-parity from
// validator count. nil = supply is just the sum of funded balances (current behavior).
GenesisUseiSupply *sdk.Int

// MintTokenReleaseSchedule, when non-empty, writes the mint token_release_schedule
// (dates as day-offsets from genesis, mint_denom pinned to usei) and pins the epoch
// clock so the first release fires on the schedule's start date. Empty = mint stays
// at its module default.
MintTokenReleaseSchedule []MintRelease

// GovParams, when non-nil, overrides the gov module's voting/deposit/tally params.
// Required for the gov suites: the default 2-day voting period never resolves their
// short-sleep vote cases.
GovParams *GovParams
}

// MintRelease is one token_release_schedule entry, expressed as day-offsets from the
// network's genesis date. Offsets (not absolute date strings) let the harness derive
// the schedule and the epoch clock from one reference instant, so the first release
// fires on the schedule's start date deterministically.
type MintRelease struct {
StartDaysFromGenesis int // 0 = genesis day
EndDaysFromGenesis int // must be > StartDaysFromGenesis
Amount sdk.Int // token_release_amount
}

// GovParams overrides the gov module genesis params. nil leaves the module default.
type GovParams struct {
VotingPeriod time.Duration
ExpeditedVotingPeriod time.Duration
MaxDepositPeriod time.Duration
Quorum sdk.Dec
Threshold sdk.Dec
ExpeditedQuorum sdk.Dec
ExpeditedThreshold sdk.Dec
}

// DockerLocalnodeGovParams returns the gov params the docker localnode sets
// (step2_genesis.sh): 0.5/0.5 normal quorum/threshold, 0.9/0.9 expedited, and
// 30s/15s/100s voting/expedited/deposit periods — what the gov suites resolve against.
func DockerLocalnodeGovParams() *GovParams {
return &GovParams{
VotingPeriod: 30 * time.Second,
ExpeditedVotingPeriod: 15 * time.Second,
MaxDepositPeriod: 100 * time.Second,
Quorum: sdk.MustNewDecFromStr("0.5"),
Threshold: sdk.MustNewDecFromStr("0.5"),
ExpeditedQuorum: sdk.MustNewDecFromStr("0.9"),
ExpeditedThreshold: sdk.MustNewDecFromStr("0.9"),
}
}

// ExtraKey is a non-validator genesis account the harness creates and funds — a
Expand Down Expand Up @@ -194,10 +247,14 @@ func Start(ctx context.Context, opts Options) (_ *Network, retErr error) {

enc := app.MakeEncodingConfig()
gb := &genesisBuilder{
codec: enc.Marshaler,
txConfig: enc.TxConfig,
chainID: opts.ChainID,
bondDenom: sdk.DefaultBondDenom,
codec: enc.Marshaler,
txConfig: enc.TxConfig,
chainID: opts.ChainID,
bondDenom: sdk.DefaultBondDenom,
useiSupplyTarget: opts.GenesisUseiSupply,
mintSchedule: opts.MintTokenReleaseSchedule,
govParams: opts.GovParams,
mintRef: time.Now().UTC(), // one reference instant for the mint schedule + epoch clock
}

if err := net.provisionNodes(enc, gb); err != nil {
Expand Down Expand Up @@ -391,6 +448,17 @@ func (net *Network) startNode(ctx context.Context, n *node, enc encoding) error
{PubKey: tmPub, Address: tmPub.Address(), Name: n.moniker, Power: 100},
}
}
// Match the docker localnode's block-gas pair — 35M max_gas / 70M max_gas_wanted
// (its 2x ratio avoids false-positive gas rejections). The defaults are unlimited
// max_gas (which the EVM reports as a 100M block gaslimit) and 50M max_gas_wanted
// (too tight for the 35M cap — a batch whose declared gas exceeds 50M but used gas
// stays under 35M would fail ProcessProposal's checkTotalBlockGas). Set here, on the
// genDoc the node starts with, because collectGentxs's re-export resets ConsensusParams.
if genDoc.ConsensusParams == nil {
genDoc.ConsensusParams = tmtypes.DefaultConsensusParams()
}
genDoc.ConsensusParams.Block.MaxGas = 35_000_000
genDoc.ConsensusParams.Block.MaxGasWanted = 70_000_000

tmNode, err := tmnode.New(
ctx, n.tmCfg, func() {}, theApp, genDoc,
Expand Down Expand Up @@ -451,6 +519,9 @@ func buildNodeConfig(nodeDir, moniker string, timeoutCommit time.Duration) (*con
tmCfg.Moniker = moniker
tmCfg.SetRoot(nodeDir)
tmCfg.Consensus.UnsafeCommitTimeoutOverride = timeoutCommit
// Force the kv tx-index sink on. `-b block` (BroadcastTxCommit) polls the tx
// index, not the event bus, so YAML suites using it (wasm) hang without this —
// a mode-based config would give a validator the null indexer.
tmCfg.TxIndex = config.TestTxIndexConfig()
// loopback conn-tracker ceiling: loopback collapses every peer onto 127.0.0.1,
// so the router's IP-keyed conn-tracker counts all N-1 inbound on one key.
Expand Down
12 changes: 7 additions & 5 deletions integration_test/contracts/create_tokenfactory_denoms.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#!/bin/bash

seidbin=$(which ~/go/bin/seid | tr -d '"')
keyname=$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].name" | tr -d '"')
keyaddress=$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].address" | tr -d '"')
# SEIDBIN / FIXTURE_SIGNER let a non-docker caller repoint the binary + signer
# without changing docker's behavior (both unset → the original computed values).
seidbin=${SEIDBIN:-$(which ~/go/bin/seid | tr -d '"')}
keyname=${FIXTURE_SIGNER:-$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].name" | tr -d '"')}
keyaddress=$(printf "12345678\n" | $seidbin keys show "$keyname" -a | tr -d '"')
chainid=$($seidbin status | jq ".NodeInfo.network" | tr -d '"')
seihome=$(git rev-parse --show-toplevel | tr -d '"')

Expand Down Expand Up @@ -53,7 +55,7 @@ done
first_set_block_height=$($seidbin status | jq -r '.SyncInfo.latest_block_height')
echo "$first_set_block_height" > $seihome/integration_test/contracts/tfk_first_set_block_height.txt

sleep 5
sleep "${FIXTURE_SETTLE_SECONDS:-5}"

# create second set of tokenfactory denoms
for i in {11..20}
Expand All @@ -66,7 +68,7 @@ done
second_set_block_height=$($seidbin status | jq -r '.SyncInfo.latest_block_height')
echo "$second_set_block_height" > $seihome/integration_test/contracts/tfk_second_set_block_height.txt

sleep 5
sleep "${FIXTURE_SETTLE_SECONDS:-5}"

# create third set of tokenfactory denoms
for i in {21..30}
Expand Down
2 changes: 1 addition & 1 deletion integration_test/contracts/deploy_flatkv_evm_fixture.sh
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ if [ -z "$deploy_tx" ]; then
fi
deploy_receipt=$(wait_for_receipt "$deploy_tx")
require_success_receipt "contract deployment" "$deploy_receipt"
printf "%s\n" "$deploy_receipt" > "$out_dir/flatkv_evm_deploy_receipt.json"
printf "%s\n" "$deploy_receipt" > /tmp/flatkv_evm_deploy_receipt.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] This debug receipt is now written to a fixed /tmp/flatkv_evm_deploy_receipt.json (not $TMPDIR, no per-run/per-user suffix). It's write-only (nothing reads it), so there's no correctness impact, but on a shared CI host concurrent runs would clobber the same file. Consider a unique path (e.g. ${TMPDIR:-/tmp}/flatkv_evm_deploy_receipt.$$.json) if that ever matters. Nit.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] This redirect was changed from $out_dir/flatkv_evm_deploy_receipt.json to a hardcoded /tmp/flatkv_evm_deploy_receipt.json, which also changes docker's behavior (contradicting the "docker byte-for-byte" claim). It appears harmless — grep shows this receipt file is only written, never read — but the fixed /tmp path could collide between two runs sharing a CI host. Since it's an unused debug artifact, consider dropping the write entirely, or using a per-run temp path.


contract_addr=$(printf "%s\n" "$deploy_receipt" | jq -r '.result.contractAddress // empty')
if [ -z "$contract_addr" ] || [ "$contract_addr" = "null" ]; then
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#!/bin/bash

seidbin=$(which ~/go/bin/seid | tr -d '"')
keyname=$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].name" | tr -d '"')
# SEIDBIN / FIXTURE_SIGNER let a non-docker caller repoint the binary + signer
# without changing docker's behavior (both unset → the original computed values).
seidbin=${SEIDBIN:-$(which ~/go/bin/seid | tr -d '"')}
keyname=${FIXTURE_SIGNER:-$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].name" | tr -d '"')}
chainid=$($seidbin status | jq ".NodeInfo.network" | tr -d '"')
seihome=$(git rev-parse --show-toplevel | tr -d '"')
migration=$1
Expand Down
Loading
Loading