关于payable关键字用于修饰地址变量的解释
当payable用于修饰函数,它有明确的作用和语义,被修饰的函数在被调用时(被调用解析逻辑中的过滤器拦截成功),如果value不为空并且该函数是payble则会执行转账和函数调用逻辑。这个作用是实质性的。
但是作为转账发起方,它现在要向某个地址发起转账,收款方是否能够接收这笔转账,取决于收款方的合约逻辑安排,这个逻辑安排对转账发起方是未知的,现在它用payable修饰这个地址,只是表达一种“希望这个地址能够接收我的转账”这样一种意图而已,这种意图用在参数传递的场景下有微弱的意义:告诉调用者,我会用这个地址发起转账,希望你能保证对方有收款的能力。这就是payble的作用。但几乎没有用。收款逻辑安排很复杂,是一个过滤器链条,发起方不同的转账方式会导致转账成功失败的不同结果,函数通过将地址参数修饰为payble是希望调用者提供某种保障,但调用者并不具备足够信息。是否成功,跟你自己的转账方式还有关系。所以这种契约关系中的责任分配就更加费解。
如果把payble语义限定一下:它声明被调用合约有能力接收calldata为空这种方式的转账调用,似乎语义能够略清晰一些,它在要求address这个合约安排了receive()函数,或者payble的fallback。但也只是略清晰而已,对于形成有约束力的契约关系不具备值得考虑的作用。
当使用call函数来转账时,payble修饰符已经不需要,这个事实也反映出solidity语言设计者的意图;当初安排address的payble修饰符,应该就是因为send和transfer而设的,也就是针对calldata为空的调用而言的,也就是在声明这个address的合约有receive()或者payable的fallback。但如上所言,这并没有什么卵用。
所以是垃圾设计安排。但也情有可原,历史问题。
另外关于send和transfer也不要去记。比如同to.send(uamount)只是call{value:amount, gas:2300}("")而已。send讲call的success返回值直接返回,transfer判断success,success为false时进行revert。这样理解一下就够了。收款方并不知道你是call还是send还是transfer,没有区别。