@@ -12,6 +12,7 @@ import (
1212 "strings"
1313 "sync"
1414 "testing"
15+ "time"
1516
1617 "github.com/ethereum/go-ethereum/accounts/abi"
1718 "github.com/ethereum/go-ethereum/common"
@@ -633,3 +634,93 @@ func TestGetMetadata_EmptyResult(t *testing.T) {
633634func parseABI () (abi.ABI , error ) {
634635 return abi .JSON (strings .NewReader (identityRegistryABI ))
635636}
637+
638+ // TestWaitForAgent_RetriesUntilOwnerVisible verifies that WaitForAgent keeps
639+ // polling ownerOf until the reader returns a successful result, simulating
640+ // the read-side staleness window between Register's WaitMined (write upstream)
641+ // and a subsequent setMetadata estimateGas (read upstream).
642+ func TestWaitForAgent_RetriesUntilOwnerVisible (t * testing.T ) {
643+ var attempts int
644+ owner := common .HexToAddress ("0x2FbFe6cF08Ac224f97915ecF07eE29Be0b213f51" )
645+
646+ parsedABI , err := parseABI ()
647+ if err != nil {
648+ t .Fatalf ("parseABI: %v" , err )
649+ }
650+
651+ handlers := map [string ]func ([]json.RawMessage ) (json.RawMessage , error ){
652+ "eth_chainId" : func (_ []json.RawMessage ) (json.RawMessage , error ) {
653+ return json .RawMessage (`"0x14a34"` ), nil
654+ },
655+ "eth_call" : func (_ []json.RawMessage ) (json.RawMessage , error ) {
656+ attempts ++
657+ if attempts < 3 {
658+ // Simulate ERC721NonexistentToken on first two calls (read
659+ // upstream not yet caught up).
660+ return nil , fmt .Errorf ("execution reverted" )
661+ }
662+ // Third call: encode owner as ownerOf return.
663+ ownerBytes , encErr := parsedABI .Methods ["getAgentWallet" ].Outputs .Pack (owner )
664+ if encErr != nil {
665+ return nil , encErr
666+ }
667+ return json .RawMessage (fmt .Sprintf ("%q" , "0x" + common .Bytes2Hex (ownerBytes ))), nil
668+ },
669+ }
670+
671+ srv := mockRPC (t , handlers )
672+ defer srv .Close ()
673+
674+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
675+ defer cancel ()
676+
677+ client , err := NewClient (ctx , srv .URL )
678+ if err != nil {
679+ t .Fatalf ("NewClient: %v" , err )
680+ }
681+ defer client .Close ()
682+
683+ got , err := client .WaitForAgent (ctx , big .NewInt (5196 ), 20 * time .Second )
684+ if err != nil {
685+ t .Fatalf ("WaitForAgent: %v after %d attempts" , err , attempts )
686+ }
687+ if got != owner {
688+ t .Errorf ("expected owner %s, got %s" , owner , got )
689+ }
690+ if attempts < 3 {
691+ t .Errorf ("expected at least 3 attempts (2 reverts + 1 success), got %d" , attempts )
692+ }
693+ }
694+
695+ // TestWaitForAgent_TimeoutReturnsError verifies that persistent reverts
696+ // surface as a timeout error.
697+ func TestWaitForAgent_TimeoutReturnsError (t * testing.T ) {
698+ handlers := map [string ]func ([]json.RawMessage ) (json.RawMessage , error ){
699+ "eth_chainId" : func (_ []json.RawMessage ) (json.RawMessage , error ) {
700+ return json .RawMessage (`"0x14a34"` ), nil
701+ },
702+ "eth_call" : func (_ []json.RawMessage ) (json.RawMessage , error ) {
703+ return nil , fmt .Errorf ("execution reverted" )
704+ },
705+ }
706+
707+ srv := mockRPC (t , handlers )
708+ defer srv .Close ()
709+
710+ ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
711+ defer cancel ()
712+
713+ client , err := NewClient (ctx , srv .URL )
714+ if err != nil {
715+ t .Fatalf ("NewClient: %v" , err )
716+ }
717+ defer client .Close ()
718+
719+ _ , err = client .WaitForAgent (ctx , big .NewInt (5196 ), 3 * time .Second )
720+ if err == nil {
721+ t .Fatal ("expected timeout error, got nil" )
722+ }
723+ if ! strings .Contains (err .Error (), "timed out" ) {
724+ t .Errorf ("expected 'timed out' in error, got: %v" , err )
725+ }
726+ }
0 commit comments